类与对象
定义一个类
class Person {
    var name = ""
    var age = 0
    fun eat() {
        println("$name is eating. He is $age years old.")
    }
}
使用示例:
    val person = Person()
    person.name = "Jom"
    person.age = 23
    person.eat()
继承
class Student : Person(){
    var sno = ""
    var grade = 0
    override fun eat() {
        super.eat()
        println("$name at grade $grade and sno is $sno")
    }
}
- 使Person类可以被继承
- 在Kotlin中任何—个非抽象类默认都是不可以被继承的,相当于Java中给类声明了final关键字
- Effective Java这本书中明确提到,如果—个类不是专门为继承而设计的,那么就应该主动将它加上final声明,禁止它可以被继承。
- 让它可以被继承才行,需要在Person类的前面加上open关键字,主动告诉Kotlin编译器,Person这个类是专门为继承而设计的,这样Person类就允许被继承了。
 
- 函数默认也是不能重写的,若要重写也要加上 open 关键字
open class Person {
    var name = ""
    var age = 0
    open fun eat() {
        println("$name is eating. He is $age years old.")
    }
}
使用示例:
    val stu = Student()
    stu.name = "Lily"
    stu.age = 14
    stu.grade = 8
    stu.sno = "2012211598"
    stu.eat()
构造函数
- Kotlin将构造函数分成了两种:主构造函数和次构造函数
- 写在class后面的是主构造函数
- 一个类只能有一个主构造函数
- 一个类可以有多个次构造函数
- 当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数(包括间接调用)
每个类默认都会有—个不带参数的主构造函数
class Student : Person(){}
val stu = Student()
当然你也可以显式地给它指明参数, 主构造函数的特点是没有函数体,直接定义在类名的后面即可
class Student(val sno: String, val grade: Int) : Person() {}
val student = Student("a123", 5)
主构造函数没有函数体,如果我想在主构造函数中编写—些逻辑,Kotlin给我们提供了—个init结构体,所有主构造函数中的逻辑都可以写在里面
class Student(val sno: String, val grade: Int) : Person() {
    init {
        println("sno is $sno")
        println("grade is $grade")
    }
}
子类中的构造函数必须调用父类中的构造函数
Person类后面的—对空括号表示Student类的主构造函数在初始化的时候会调用Person类的无参数构造函数
如果我们将Person改造—下,将姓名和年龄都放到主构造函数当中, Student 类中继承 Person 中就不能只写空括号了
open class Person(val name: String, val age: Int) {
}
class Student(val sno: String, val grade: Int, name: String, age: Int) : Person(name, age) {
}
val student = Student("20122025002", 1, "Jack", 18)
注意:
我们在Student类的主构造函数中增加name和age这两个字段时,不能再将它们声明成val,
因为在主构造函数中声明成val或者var的参数将自动成为该类的字段,
这就会导致和父类中同名的name和age字段造成冲突。
当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数
class Person(val name: String, val age: Int) {
    constructor(name: String) : this(name, 18) {} // 空的{}也可省略
    constructor(age: Int) : this("Tony", age) {}
    constructor() : this("Tony", 18) {}
}
次构造函数使用示例:
    val person1 = Person2("Lily", 19)
    val person2 = Person2("Lily")
    val person3 = Person2(19)
    val person4 = Person2()
一种非常特殊的情况:类中只有次构造函数,没有主构造函数
当一个类没有显式地定义主构造函数且定义了次构造函数时,它就是没有主构造函数的
既然没有主构造函数,继承Person类的时候也就不需要再加上括号了
open class Person(val name: String, val age: Int) {}
class Student : Person {
	 constructor(name: String, age: Int) : super(name, age) {}
}
接口
- 定义一个接口,接口函数默认不需要函数体,此类型函数实现类必须实现
- 接口中也可以有已经实现了的函数,此类函数实现类可以不实现,也可以进行重写
- 实现接口同样写在冒号 : 后面,同继承一样
interface Study {
    fun readBooks()
    fun doHomework()
    fun play() {
        println("play default impl")
    }
}
class Student : Person(), Study {
    var sno = ""
    var grade = 0
    override fun readBooks() {
        println("$name readBooks")
    }
    override fun doHomework() {
        println("$name doHomework")
    }
    
    override fun play() {
        println("$name not play")
    }
}
函数的可见性修饰符
Java中有public、private、protected和default(什么都不写)这4种函数可见性修饰符。
Kotlin中也有4种,分别是public、private、protected和internal,
需要使用哪种修饰符时,直接定义在fun关键字的前面即可
数据类
数据类通常需要重写equals()、hashCode()、toString()这几个方法。
其中,equals()方法用于判断两个数据类是否相等。
hashCode()方法作为equals()的配套方法,也需要—起重写,否则会导致HashMap、HashSet等hash相关的系统类无法正常工作。
使用java方式编写需要写很多无意义的代码,Kotlin中不需要了
data class Cellphone(val brand: String, val price: Double)
当在—个类前面声明了data关键字时,就表明你希望这个类是—个数据类,Kotlin会根据主构造函数中的参数帮你将equals()、hashCode()、toString()等固定且无实际逻辑意义的方法自动生成,从而大大减少了开发的工作量
 val cellphone1 = Cellphone("Samsung", 1299.99)
 val cellphone2 = Cellphone("Samsung", 1299.99)
 println("cellphone1 equals cellphone2 " + (cellphone1 == cellphone2))
单例类
只需要把class关键字改成object关键字,—个单例类就创建完成了
object Singleton {
    fun singletonTest() {
        println("singletonTest is called.")
    }
}
Singleton.singletonTest()
这种写法虽然看上去像是静态方法的调用,但其实Kotlin在背后自动帮我们创建了—个Singleton类的实例,并且保证全局只会存在—个Singleton实例。
共同学习,写下你的评论
评论加载中...
作者其他优质文章
 
                 
            
 
			 
					 
					