栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Kotlin学习笔记——(五)类

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Kotlin学习笔记——(五)类

注:编码工具为IntelliJ

目录

类的继承和方法重写

智能转换:is as

object类型

object表达式

伴生对象:companion object

嵌套类和内部类

数据类型:data class

自定义解构函数

运算符重载

枚举:enum class

密封类:sealed class


类的继承和方法重写

        Kotlin的类和方法默认都是public final的,如果想要让类可以被继承、方法可以被重写,需要在类声明和方法声明前添加open关键字。

open class base(var info: String){
    open fun show(){
        println("base info:$info")
    }
}

class Subbase():base("World from Sub"){
    override fun show() {
        super.show()
        println("sub info:$info")
    }
}

fun main() {
    val b: base = base("Universe from base")
    val b2: base = Subbase()
    b.show()
    b2.show()
}

输出:

base info:Universe from base
base info:World from Sub
sub info:World from Sub

智能转换:is as

        Kotlin中判断某个对象是否某种数据类型的对象时使用is,相当于Java的instanceof,如果该对象确实是该数据类型的对象,is判断后会智能转换为该数据类型对象,可以直接使用该对象;

        Kotlin中使用as将一种类型对象转换为另一种数据类型对象,相当于Java的强制类型转换。

open class base2(var info: String){
    open fun show(){
        println("base2 info: $info")
    }
}

class Subbase2(): base2("Subbase2"){
    override fun show() {
        println("subbase2 info: $info")
    }

    fun unique(){
        println("subbase2特有方法")
    }
}

class Subbase21(): base2("Subbase22"){
    override fun show() {
        println("subbase22 info: $info")
    }

    fun test(){
        println("subbase21特有方法")
    }
}

fun traverse(b: base2){
    when (b) {
        is Subbase2 -> {
            b.unique()// is判断后智能转换为Subbase2
        }
        is Subbase21 -> {
            b.test()// is判断后只能转换为Subbase21
        }
        else -> {
            b.show()
        }
    }
}

fun main() {
    val b: base2 = base2("base2")
    val b2: base2 = Subbase2()
    val b3: base2 = Subbase21()
    // 只有as转换后,才能调用Subbase2的特有方法
    (b2 as Subbase2).unique()
    // 只有as转换后,才能调用Subbase21的特有方法
    (b3 as Subbase21).test()

    println("---------------------------------")
    traverse(b)
    traverse(b2)
    traverse(b3)
}

输出:

subbase2特有方法
subbase21特有方法
---------------------------------
base2 info: base2
subbase2特有方法
subbase21特有方法

object类型
object XXXUtils{
    fun op(input: String){
        println("handle $input via op func")
    }
}

fun main() {
    val x = XXXUtils
    XXXUtils.op("输入")
}

输出:

handle 输入 via op func

反编译为Java代码:

public final class XXXUtils {
   @NotNull
   public static final XXXUtils INSTANCE;

   public final void op(@NotNull String input) {
      Intrinsics.checkNotNullParameter(input, "input");
      String var2 = "handle " + input + " via op func";
      boolean var3 = false;
      System.out.println(var2);
   }

   private XXXUtils() {
   }

   static {
      XXXUtils var0 = new XXXUtils();
      INSTANCE = var0;
   }
}

public final class ObjectTestKt {
   public static final void main() {
      XXXUtils x = XXXUtils.INSTANCE;
      XXXUtils.INSTANCE.op("输入");
   }

   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }
}

        看反编译的Java代码,可以发现,XXXUtils类内部会声明一个public static的XXXUtils变量,并在static代码框中创建对象,之后的调用XXXUtils类的成员都用这个对象,有点类似于Java的单例。object类型直接用 类型名. 的格式访问成员,类似于Java调用静态成员。

object表达式

        kotlin没有匿名内部类,可以用object表达式定义对象,实现类似的效果。

fun main() {
    val i = object : I{
        override fun test() {
            println("object expression test")
        }
    }
    i.test()
}

输出:

object expression test

Java的某些只有一个方法的接口可以有另外一种定义对象的方式,但Kotlin的只含有一个函数的接口不可以。

fun main() {
    val run = object: Runnable{
        override fun run() {
            println("run")
        }
    }
    val run2 = Runnable {
        println("run2")
    }
    run.run()
    run2.run()
}

输出:

run
run2

伴生对象:companion object

        Kotlin中没有static关键字,可以用伴生对象代替。

class CompanionObjectTest{
    companion object {
        var TAG = "PRINT"

        fun show(info: String){
            println("info: $info")
        }
    }
}

fun main() {
    CompanionObjectTest.show("test companion object")
    println(CompanionObjectTest.TAG)
}

输出:

info: test companion object
PRINT

嵌套类和内部类

        Kotlin的类内部定义的没有inner修饰的类是嵌套类,相当于Java类内部定义的static类;

        Kotlin的类内部定义的有inner修饰的类是内部类,相当于Java的内部类。

class Outer {
    class Nested {
        fun show() {
            println("Nested")
        }
    }

    inner class Inner {
        fun show() {
            println("Inner")
        }
    }
}

fun main() {
    Outer.Nested().show()
    Outer().Inner().show()
}

输出:

Nested
Inner

数据类型:data class

        数据类是Kotlin提供的为了方便开发人员开发的类似于JavaBean的类。

        数据类的特点:

                1、类声明后会自动生成主构造函数参数相关的getter、setter、componetN系列(解构用)、copy、equals、hashCode、toString方法;

                2、主构造函数参数必须带var/val修饰符;

                3、不能在类声明前加sealed/abstract/open/inner等修饰符。

data class Student(var name: String, var age: Int, var gender: Char)

fun main() {
    val stu = Student("gg", 14, 'F')
    println(stu)
    val(name, age, gender) = stu// 解构 通过componentN系列函数实现
    println("name:$name, age:$age, gender:$gender")
    val(n, a, _) = stu// 不想解构的函数可以用_屏蔽
    println("name:$n, age:$a")
}

输出:

Student(name=gg, age=14, gender=F)
name:gg, age:14, gender:F
name:gg, age:14

反编译为Java代码:

public final class Student {
   @NotNull
   private String name;
   private int age;
   private char gender;

   @NotNull
   public final String getName() {
      return this.name;
   }

   public final void setName(@NotNull String var1) {
      Intrinsics.checkNotNullParameter(var1, "");
      this.name = var1;
   }

   public final int getAge() {
      return this.age;
   }

   public final void setAge(int var1) {
      this.age = var1;
   }

   public final char getGender() {
      return this.gender;
   }

   public final void setGender(char var1) {
      this.gender = var1;
   }

   public Student(@NotNull String name, int age, char gender) {
      Intrinsics.checkNotNullParameter(name, "name");
      super();
      this.name = name;
      this.age = age;
      this.gender = gender;
   }

   @NotNull
   public final String component1() {
      return this.name;
   }

   public final int component2() {
      return this.age;
   }

   public final char component3() {
      return this.gender;
   }

   @NotNull
   public final Student copy(@NotNull String name, int age, char gender) {
      Intrinsics.checkNotNullParameter(name, "name");
      return new Student(name, age, gender);
   }

   // $FF: synthetic method
   public static Student copy$default(Student var0, String var1, int var2, char var3, int var4, Object var5) {
      if ((var4 & 1) != 0) {
         var1 = var0.name;
      }

      if ((var4 & 2) != 0) {
         var2 = var0.age;
      }

      if ((var4 & 4) != 0) {
         var3 = var0.gender;
      }

      return var0.copy(var1, var2, var3);
   }

   @NotNull
   public String toString() {
      return "Student(name=" + this.name + ", age=" + this.age + ", gender=" + this.gender + ")";
   }

   public int hashCode() {
      String var10000 = this.name;
      return ((var10000 != null ? var10000.hashCode() : 0) * 31 + Integer.hashCode(this.age)) * 31 + Character.hashCode(this.gender);
   }

   public boolean equals(@Nullable Object var1) {
      if (this != var1) {
         if (var1 instanceof Student) {
            Student var2 = (Student)var1;
            if (Intrinsics.areEqual(this.name, var2.name) && this.age == var2.age && this.gender == var2.gender) {
               return true;
            }
         }

         return false;
      } else {
         return true;
      }
   }
}

自定义解构函数

        可以为普通类定义解构函数,实现解构操作,componentN函数要从component1开始。

        解构函数要用operator修饰。

        解构函数的数目可以不和成员变量的数目一致,顺序也可以不和成员变量声明的顺序一致。如下面的代码所示,总共三个成员变量name,age,gender,但只声明了两个解构函数,且第一个解构函数返回的是gender,和成员变量声明的顺序不一致。

class ComponentTest(var name:String, var age: Int, var gender: Char){
    operator fun component1(): Char{
        return gender
    }
    operator fun component2(): Int{
        return age
    }
}

fun main() {
    val c = ComponentTest("name", 1, 'M')
    println("name:${c.name}, age:${c.age}, gender:${c.gender}")

    val (gender, age) = c
    println("gender:$gender, age:$age")
}

输出:

name:name, age:1, gender:M
gender:M, age:1

运算符重载

        用于对象之间+、-、*、/等操作。

class Point(var x: Int, var y: Int){
    
    // +
    operator fun plus(another: Point) : Point{
        return Point(x + another.x, y + another.y)
    }

    // -
    operator fun minus(another: Point) : Point{
        return Point(x - another.x, y - another.y)
    }

    override fun toString(): String {
        return "Point{x:$x, y:$y}"
    }
}

fun main() {
    val p1 = Point(4, 8)
    val p2 = Point(3, 9)
    val sum = p1 + p2
    val diff = p1 - p2
    println(sum)
    println(diff)
}

输出:

Point{x:7, y:17}
Point{x:1, y:-1}

枚举:enum class

        Kotlin中的枚举也是类,用enum class定义,枚举类可以有构造函数、成员变量、成员函数。构造函数只有在枚举类内部定义枚举项的时候可以使用,其他的时候不能使用;成员变量和成员函数可以跟普通类的一样使用。

enum class Shape(var cname: String){
    TRIANGLE("三角形"),
    CIRCLE("圆形"),
    RECTANGLE("矩形"),
    SQUARE("正方形");

    var state = 1

    fun show(){
        println("$this cname is $cname, state is $state")
    }
}

fun main() {
    Shape.CIRCLE.state = 0
    Shape.CIRCLE.show()
    println(Shape.RECTANGLE)
    Shape.SQUARE.cname = "square"
    println(Shape.SQUARE.cname)
}

输出:

CIRCLE cname is 圆形, state is 0
RECTANGLE
square

        用when判断枚举类型,可以不写else分支,编译器可以自动推断是否覆盖所有枚举项。下面要说的密封类类似。

密封类:sealed class
sealed class Color{
    object red: Color()
    object green: Color()
    object blue: Color()
    class other(val name: String): Color()
}

fun show(color: Color) =
    when(color)
    {
        is Color.red -> "红色"
        is Color.green -> "绿色"
        is Color.blue -> "蓝色"
        is Color.other -> color.name// 智能转换
    }


fun main() {
    println(show(Color.red))
    println(show(Color.green))
    println(show(Color.blue))
    println(show(Color.other("紫色")))
    println(show(Color.other("粉色")))
}

输出:

红色
绿色
蓝色
紫色
粉色

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/439426.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号