阅读 32

Kotlin劝退指南——类与接口(一)

Kotlin 类与接口

Kotlin的类与接口与Java的类似,通过classinterface声明类和接口。Kotlin一向以简洁著称,所以它也优化了Java中的类型的声明方式,并且在语言层面引入了一个Java中从未有过的概念——属性访问器。

Compare with java

  1. 一个文件中可以定义多个类文件

    Java中定义类,默认一个文件中只能存在一个public的类,若要声明多个类,那么多余的类需要以静态内部类的形式存在,或者声明为非公开的类(编译会生成多个字节码文件)。

    class Outter
    {
        
    }
    public class Foo
    {
        public static class Inner
        {
            
        }
    }
    复制代码

    Kotlin中,一个文件可以存在多个类,并且这些类不需要额外的描述符进行描述。

    class Foo
    {
    }
    class Person
    {
        
    }
    class Student
    {
        
    }
    复制代码

    通过编译发现,在一个文件中定义多个类时,编译之后仍然是生成多个字节码文件

  2. 主构造函数

    Kotlin允许你在类名称后面紧跟一个构造函数,这个函数被称为主构造函数(Primary constructor)

    class Person(_name : String, _age : Int)
    {
        var name : String = _name
        var age : Int = _age
    }
    复制代码

    同时你也可以直接在构造函数中声明类的字段。

    class Person(var name : String, var age : Int){}
    复制代码

    多个构造函数伴随主构造函数,Kotlin的构造函数名字叫做constructor,而且必须使用constructor声明构造函数,不可以像Java那样声明一个与类名相同的函数作为构造函数。

    class Person(var name : String, var age : Int)
    {
        constructor() : this("default", 0)
        constructor(_age : Int) : this("default", _age)
        constructor(_name : String) : this(_name, 0)
    }
    复制代码

    当然你也可以选择使用Java-like的构造函数

    class Person
    {
        var name: String
        constructor()
        {
            name = "default";
        }
        constructor(_name: String)
        {
            name = _name;
        }
    }
    复制代码
  3. 字段必须初始化

    在Java中,一个类中的字段,若在构造函数和初始化代码块中都没有对其进行初始化,那么字段将会被赋予默认值,Java中引用类型字段的默认值为null, 基本类型的默认值为0(布尔值为false)。

    在Kotlin中,字段若不对其进行初始化操作,那么编译将会出错。(Kotlin是一门空安全的语言,Kotlin不喜欢null),所以当你声明了一个字段,你必须在初始化代码块或者构造函数中对其进行初始化。

    在Kotlin中,若不能够及时的对字段进行初始化操作,那该怎么办呢?这种情况一般分为四类

    • 声明为抽象类

    • 字段为值类型(以val声明的字段,不可变引用),这种情况可以为其附加一个getter访问器函数,而不对其进行显示的初始化

      class Foo
      {
          val isTrue: Int
          get(){return xxxxxx};
      }
      复制代码
    • 使用lateinit修饰的字段,可以在不对其字段进行初始化操作,但在字段使用前仍未对其进行初始化操作,那么访问该字段将会抛出异常。同时被lateinit修饰的字段不允许自定义getter&setter

    • 通过by。

  4. 默认不可被继承

    在Java中,若一个类被final修饰,那么它将不会拥有派生类,也没有任何一个类可以继承自它。

    在Kotlin中,我们声明的类都是不可以被继承的,换言之,它们默认会加上final的修饰符。如果你想让一个类拥有派生类,那么你需要使用open去修饰它

    class Person(var name : String) {} /* 这个类不可以被继承 */
    
    open class Person(var name : String) {} /* 这个类可以被继承 */
    复制代码
  5. 属性访问器

    这是一个java中没有的概念,但这并不是一个新概念,它类似于Java中的getter和setter。属性访问器并不是一个Kotlin这门语言独有的概念,在C#,JavaScript中也有着类似的定义。

    属性访问器在代码层面给你一种直接操作字段的感觉,但实际上,当你获取字段或者给字段赋值时,还是调用了一个方法(getter&setter)。正是由于属性访问器的存在,所以对于一些常规字段,我们不需要刻意的去添加访问修饰符,我们只需要设置getter&setter方法即可。即使你不设置getter&setter,Kotlin也会为字段提供默认的getter&setter。

    class Foo(_name: String, _age: Int)
    {
        var name: String = _name
        
        var age: Int = _age
        set(value) = field = if (value >= 0) age else 0
    }
    
    class Rectangle(_width: Int, _height: Int)
    {
        var width: Int = _width
        var height: Int = _height
        
        val isSquare: Boolean
        get() = width == height
        
        var ID: String
        get() = field + " rectangle"
         /* 划重点,不能写成ID + rectangle 也不可以调用字段的API 例如 ID.toUpperCase() */
    }
    复制代码

    **不过在使用属性访问器一定要注意,字段要用field代替,不然会造成递归代码。**Kotlin中对字段的访问默认都会去调用它的访问器函数,如果在访问器函数中恰巧访问了这个字段,那么会造成无穷尽的递归,直至爆栈。

文章分类
阅读
文章标签