类与构造函数

回到目录
项目源码 kotlin-class 项目


类声明

Kotlin 中用 class 关键字声明一个类, 跟 java 有区别的一些地方是, 你可以在同个
源文件中声明多个 public 类; 如果一个类没有 body, 那个花括号是可以省略的(比如
spring boot 中的启动类, 只是用来放注解 @SpringBootApplication);

@SpringBootApplication
class KotlinClassApplication

构造函数

在 Kotlin 中的一个类可以有一个主构造函数以及一个或多个次构造函数。主构造函数是
类头的一部分.

// 主构造函数中不加 var, val, 那么 name 和 age 只是构造函数的参数而已
class Animal constructor(name: String, age:Int?)

注意, 如果构造函数参数不加 valvar, kotlin 编译器不会将他们当成类属性, 即
不会自动生成 getter setter 方法. 所以一般都要加上 val.

// 如果不加 var, val
// 需要再写一下属性初始化代码才行
class Dog (name: String, age: Int?) {
    val name = name
    val age = age
    // 属性必须初始化, 除非使用 lateinit var 标记为延迟初始化的属性
    lateinit var owner: String
}

如果属性不写在主构造函数中, 那就必须初始化; 除非加上 lateinit var 标记

新建一个对象不需要使用 new 关键字, 直接调用构造函数就可以了.

    @Test fun testConstruct() {
        val person = Person("codergege", null)
        assertEquals("codergege", person.name)
        assertNull(person.age)
    }

可以看到, 虽然我们并没有写 getter setter 方法, 但是已经可访问属性了, 因为 kotlin
编译器已经自动为我们生成.

如果主构造函数没有任何注解或者可见性修饰符 constructor 关键字可以省略.

class Person(val name: String, val age: Int?)

如果需要在构造函数中写点逻辑, 得用 init 块. 例如:

class Person(val name: String, val age: Int?) {
    init {
        require(name.trim().length > 0) {
            "名称长度必须大于 0 !"
        }
        if(age != null) {
            require(age > 0 && age < 150) {
                "年龄必须是 (0, 150) 之间"
            }
        }
    }
}

一个对象的初始化过程里, 多个 init 块和属性初始化代码是按代码顺序执行的

class InitOrderDemo(name: String) {
    val firstProperty = "First property: $name".also(::println)
    
    init {
        println("First initializer block that prints ${name}")
    }
    
    val secondProperty = "Second property: ${name.length}".also(::println)
    
    init {
        println("Second initializer block that prints ${name.length}")
    }
}

"xxx".also() 会将调用传入的函数, 参数是 this(谁调就传谁) 并返回 this
测试这段代码:

    @Test fun testInitOrder() {
        val obj = InitOrderDemo("hello")
    }

输出是

First property: hello
First initializer block that prints hello
Second property: 5
Second initializer block that prints 5

注意到, name 这个构造函数的参数也能被用来给属性赋值.这是因为编译器最终会将所
有的 init 和属性初始化代码放进主构造函数中.

次构造函数

次构造函数通过 constructor 声明.
次构造函数(Secondary Constructor)必须通过 this 调用主构造函数, 然后把参数传过去:
当然, 如果没有主构造函数, 也可以用 this 调用其他次构造函数.

    // 非主构造函数中, 参数不允许有 val 和 var, 就像普通函数那样.
    constructor(name: String): this(name, null)

现在通过第二个构造函数创建一个对象:

        val jack = Person("Jack")
        assertEquals("Jack", jack.name)
        assertNull(jack.age)

Kotlin 中所有默认访问级别是 public 的.

如果一个类的主构造函数中所有的属性都有默认值, 那么编译器会自动再生成一个无参
的构造函数, 方便在 Spring, JPA 等框架中使用.
以前是需要加上 no-arg 插件的, 现在这个插件不是必须的了.


回到目录

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 前言 人生苦多,快来 Kotlin ,快速学习Kotlin! 什么是Kotlin? Kotlin 是种静态类型编程...
    任半生嚣狂阅读 26,345评论 9 118
  • 抽象 对象大致意味着一系列数据(属性)以及一套访问和操作这些数据的方法。使用对象而非全局变量和函数的原因有多个,下...
    Jimmy_L_Wang阅读 4,479评论 0 0
  • 面向对象编程(OOP) 在前面的章节中,我们学习了Kotlin的语言基础知识、类型系统、集合类以及泛型相关的知识。...
    Tenderness4阅读 9,919评论 1 6
  • 这是16年5月份编辑的一份比较杂乱适合自己观看的学习记录文档,今天18年5月份再次想写文章,发现简书还为我保存起的...
    Jenaral阅读 7,881评论 2 9
  • 不少男性到了中年就头发日渐稀少,以致头顶心部位几乎是“一片沙漠”。秃顶这个不算疾病的病症在男性中并不鲜见。 为什么...
    王士尤阅读 5,765评论 0 0