Kotlin——程序核心构成元素之包、类的基本语法(五)

引言

前两篇Kotlin——程序的灵魂组成之变量、属性和函数的基本语法(一)Kotlin——程序的灵魂组成之变量、属性和函数的基本语法(二)从具体结构内部总结了下Kotlin的算法基本结构的元素以及组织形式,但是程序灵魂固然重要但是没有躯体也是毫无意义的,所以这章就先总结下关于Kotlin躯体构成的各种元素——包、类和对象(里面有些术语Kotlin中不一定有我是借鉴Java的),毕竟在面向对象编程中万物皆对象,任何事物都可以进行抽象和封装成一个对象来表达它所具有的属性和特征,Kotlin系列文章链接:

一、Package 包

Kotlin中的包和Java中的包概念大同小异,都是类中的顶层结构。类的源文件通常都是以包名开头的,源⽂件所有内容(⽆论是类还是函数)都包含在声明的包内。 如果没有指明包,该⽂件的内容属于⽆名字的默认包。

1、默认自动Kotlin系统包

和Java一样,每次建立一个Kotlin文件的时候系统都会自动导入一些基础包,Kotlin默认下会导入:
这里写图片描述

2、导入包基本语法

  • import 单个完整包名
  • import 单个完整包名.*下所有的
  • import 包名 as 新包名 ——重命名包名
import foo.Bar // 现在 Bar 可以不⽤限定符访问
//也可以导⼊⼀个作⽤域下的所有内容(包、类、对象等):
import foo.* // “foo”中的⼀切都可访问
//如果出现名字冲突,可以使⽤ as 关键字在本地重命名冲突项来消歧义:
import foo.Bar // Bar 可访问
import bar.Bar as bBar // bBar 代表“bar.Bar”

3、Kotlin支持导入的元素

  • 顶层的方法和属性
  • 在对象声明中的方法和属性
  • 枚举常量

二、类

在这里插入图片描述
Kotlin中类的成员可以分为五大类:构造函数、初始化块函数属性嵌套类和内部类及对象声明

  • 构造函数——包含主构造函数(不能包含任何的代码)、次构造函数
  • 初始化代码块——一个类体可以有多个以init 关键字作为前缀的初始化代码块(initializer blocks),按照声明的顺序执行,可执行一些需要在主构造函数中完成的初始化的操作,初始化代码块和类体都可以直接访问主构造函数中的形参,每当生成对象时会自动执行初始化代码块。
  • 函数
  • 属性——使用val或者var定义的变量,可根据需求使用可见性修饰符修饰。
  • 嵌套类和内部类
  • 对象声明

1、类定义

和Java一样 Kotlin 也使⽤关键字 class 声明类,后面紧跟类名、类头和类体。其中大括号{}中的 的内容成为类体,类名与类体之间的内容称为类头(类头和类体是可以省略的)

open class CrazyBlog public @MoAnotation constructor(name :String){
	....
}

但是如果不仅没有可见性修饰符和自定义注解则可以简写成

open class CrazyBlog constructor(name :String){
	....
}

构造函数也没有参数,则还可以简写成

open class CrazyBlog{
	....
}

Kotlin类中还有一个特别的类,即没有类体的类——空类

open class CrazyBlog

定义了一个 Person 类,包含两个可变变量 lastName 和 no,lastName 修改了 getter 方法,no 修改了 setter 方法

class Person {
	init{
        println("init codes")
    }
    var lastName: String = "mo"
        get() = field.toUpperCase()   // 将变量赋值后转换为大写
        set
    var no: Int = 100
        get() = field                // 后端变量
        set(value) {
            if (value < 10) {       // 如果传入的值小于 10 返回该值
                field = value
            } else {
                field = -1         // 如果传入的值大于等于 10 返回 -1
            }
        }
    var heiht: Float = 145.4f
        private set
}

// 测试
fun main(args: Array<String>) {
    var person: Person = Person()
    person.lastName = "crazy"
    println("lastName:${person.lastName}")
    person.no = 88
    println("no:${person.no}")
    person.no = 66
    println("no:${person.no}")
}

2、类的构造函数

与Java不同,在 Kotlin 中的构造函数分等级的:

  • 每个类有且只有⼀个主构造函数(primary constructor作为类头的一部分,以constructor 关键字声明。

  • 每个类有⼀个或多个次构造函数(secondary constructors),也以constructor 关键字声明次构造函数。

其中主构造函数是类头的⼀部分,它跟在类名和可选修饰符后。

2.1、主构造函数primary constructor 和 init 初始化代码块

主构造函数作为类头的⼀部分,它跟在类名(和可选的类型参数)后使用constructor 关键字声明,如果主构造函数没有任何注解或者可⻅性修饰符,可以省略这个 constructor 关键字直接跟形参列表,若没有形参则可以全部省略

class Person(firstName: String) {
	...
}

主构造函数中不能包含任何的代码,因此初始化代码可以放到init 关键字作为前缀的初始化块(initializer blocks)中,初始化代码块中也可以访问主构造函数中的参数

fun main(args: Array<String>) {
    println(Customer2("kotlin ").customerKey)
}

class Customer2 public constructor(name2: String) {
    var customerKey: String ?
    init{
        //customerKey = "${name2}"+"by crazymo_" 或者
	 	customerKey = name2+"by crazymo_"
    }
}

在 JVM 中,如果主构造函数的所有参数都有默认值,编译器会生成一个附加的无参的构造函数,这个构造函数会直接使用默认值。这使得 Kotlin 可以更简单的像 Jackson 或者 JPA 赖使用无参构造函数来创建类实例的库。

class Customer(val customerName: String = "")

2.2、次要构造函数Secondary Constructors

类除了有主构造函数还会包含一个或者N个次要构造函数,语法与主要构造函数大同小异,次要构造函数也要用constructor关键字声明,但声明位置不同(主要构造函数位于类头而是次要构造函数在类体中),而且当一个类有主构造函数时,则每一个次要构造函数都需要直接或者间接通过其他次要构造函数委托给主构造函数(委托到同⼀个类的另⼀个构造函数⽤ this 关键字即可)

class Customer2(name2: String) {
    var customerKey: String ?
    var myage: Int=0
    init{
        println("primary running")
        //customerKey = "${name2}"+"by crazymo_" 或者
	 	customerKey = name2+"by crazymo_"
    }
    constructor(name2: String,age: Int):this(name2){
        println("secondary running")
        this.myage=age //等价于 myage=age
    }
}

初始化块中本质上会成为主构造函数的一部分,而委托给主构造函数会作为次构造函数的第一条语句,因此所有初始化块中的代码都会在次构造函数体之前执行。即使该类没有主构造函数,这种委托仍会隐式发生,并且仍会执行初始化块

fun main(args: Array<String>) {
    val cus=Customer2("kotlin ",2)
    println(cus.customerKey+" age:"+cus.myage)
}
/**运行结果**/
primary running
secondary running
kotlin by crazymo_ age:2

最后,如果一个非抽象类没有声明任何构造函数(primary或​​secondary),则将自动生成没有参数的公开的主构造函数。若不希望您的类具有公共构造函数,则需要声明具有非默认可见性的空主构造函数即可(使用场景类似Java 中为了避免外部构造对象,我们把构造函数私有化)。

class Single private constructor () { ... }

2.3、构造函数小结

  • 构造函数默认的修饰符是public
  • 可以有一个主构造函数和多个次构造函数
  • 可以只有主构造函数或者只有次构造函数
  • 主、次构造函数同时存在的时候,次构造函数必须直接或者间接地委托到主构造函数
  • 没有声明主构造函数或者次构造函数时,会有一个默认的无参数主构造函数,方便创建对象,这与Java一样
  • 如果不希望类有公有构造函数,那么请私有化一个无参数主构造函数

3、类的属性

3.1、类的属性定义和lateinit延迟初始化

类的属性使用关键字 var 声明为可变的,否则使用只读关键字 val 声明为不可变,使用时对象名称 . 属性名 来引用,一般属性都有getter 和 setter,属性声明的完整语法:

var <propertyName>[: <PropertyType>] [= <property_initializer>]
    [<getter>]
    [<setter>]

getter 和 setter 都是可选,若属性类型可以从初始化语句或者类的成员函数中推断出来,则可以省去类型,val不允许设置setter函数,因为它是只读的,形如:

var allByDefault: Int? // 错误: 需要一个初始化语句, 默认实现了 getter 和 setter 方法
var initialized = 1    // 类型为 Int, 默认实现了 getter 和 setter
val simple: Int?       // 类型为 Int ,默认实现 getter ,但必须在构造函数中初始化
val inferredType = 1   // 类型为 Int 类型,默认实现 getter

非空属性必须在定义的时候初始化,kotlin提供了一种可以延迟初始化的方案,使用 lateinit 关键字修饰属性

public class MyTest {
    lateinit var subject: TestSubject

    @SetUp fun setup() {
        subject = TestSubject()
    }

    @Test fun test() {
        subject.method()  // dereference directly
    }
}

3.2、类的属性声明

类的属性声明可以有两种形式:

  • 写在类头,以 [属性修饰符] val 或者 var : 变量类型[=默认值] 形式声明
class Person2(public val firstName: String, var lastName: String, var age: Int=0) {
	// ……
}

fun main(args: Array<String>) {
    var person: Person2 = Person2("mo","cmo")
    // person.firstName="MOMO"; 报错 Val cannot be reassigned
	println("before lastName:${person.lastName}");// before lastName:cmo
    person.lastName = "CrazyMO"
    println("lastName:${person.lastName}");//lastName:CrazyMO
    println("before age:${person.age}");//before age :0
    person.age = 666666
    println("age:${person.age}");//age:666666
}
  • 写在类体内部的,但基本语法是和前面所讲的属性语法是一致的,并且也还可以使用相关修饰符。
class Person{
	val firstName: String?
	val lastName: String?
	var age: Int=0
}

未完待续

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CrazyMo_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值