kotlin笔记二

对象

kotlin中使用class关键字来声明一个类,和java一致。

1
2
3
4
5
6
7
class Person{
var name = ""
var age = 0
fun eat(){
println(name + " is eating. He is " + age + "years old.")
}
}

实例化的时候不需要new关键字

1
2
3
4
5
6
fun main(){
val p = Person()
p.name = "jack"
p.age = 19
p.eat()
}

继承与构造函数

kotlin中任何一个非抽象类默认都是不可以被继承的,要想被继承,就需要在前面加上open关键字

1
2
3
open class Person{
...
}

java中继承是关键字extends,而在kotlin中使用冒号

1
2
3
4
class Student:Person(){
var sno = ""
var grade = 0
}

构造函数主要作用是在对象实例化的时候初始化对象的成员变量,其与类名相同。跟Java一样,子类的构造函数必须调用父类的中的构造函数。上面Person类带了括号,在kotlin中是主构造函数的意思,这种写法就是遵循这个规定。
Kotlin中的构造函数分为主构造函数和次构造函数两中,分别都有不同要求。
每个类默认都有一个不带参数的主构造函数,也可以给它显式的声明参数。

1
2
3
4
5
class Student(val sno:String ,val grade:Int):Person(){
//这里声明了Student带参数的主构造函数,并且调用了Person空参数的主构造函数
}

val Jam = Student("1922123",4)

如果想在主构造函数中对参数进行操作,可以使用init结构体编写逻辑

1
2
3
4
5
6
class Student(val sno:String ,val grade:Int):Person(){
init{
println("sno is" + sno)
println("grade is " + grade)
}
}

任何一个类,只能由一个主构造函数,但是可以有多个次构造函数,次构造函数有函数体,次构造函数通过constructor关键字定义。
当一个类中既有主构造函数又有次构造函数时,所有的次构造函数必须调用主构造函数(包括间接调用)。

1
2
3
4
5
6
7
class Student(val sno: String, val grade: Int, name: String, age: Int) :Person(name, age) { 
constructor(name: String, age: Int) : this("", 0, name, age) {
}
constructor() : this("", 0) {
}
}
//这里我们定义了两个次构造函数:第一个次构造函数接收name和age参数,然后它又通过this关键字调用了主构造函数,并将sno和grade这两个参数赋值成初始值;第二个次构造函数不接收任何参数,它通过this关键字调用了我们刚才定义的第一个次构造函数,并将name和age参数也赋值成初始值,由于第二个次构造函数间接调用了主构造函数,因此这仍然是合法的。

当类中没有主构造函数的时候,不需要在继承父类时加括号

1
2
3
4
5
class Student : Person { 
constructor(name: String, age: Int) : super(name, age) {
}
}
//由于没有主构造函数,次构造函数只能直接调用父类的构造函数,上述代码也是将this关键字换成了super关键字

接口

接口的定义

1
2
3
4
interface Study{
fun readBook()
fun doHomework()
}

Java中接口的继承需要使用关键字implements,而kotlin中使用冒号就行。
Java在JDK1.8之后允许对接口中定义的函数进行默认实现,Kotlin中也支持。

1
2
3
4
5
6
7
interface Study { 
fun readBooks()
fun doHomework() {
println("do homework default implementation.")
}
}
//doHOmework可以自由选择实现或者不实现,不实现时会自动使用默认的实现逻辑。

函数的可见性修饰符

Java中有public、private、protected和default,而Kotlin中有public、private、protected和internal,使用时直接定义在fun关键字的前面。
kotlin中public时默认项,而在Java中default才是默认项。
internal只对同一模块中的类可见。
|修饰符|Java|Kotlin|
|—–|—–|——|
|public|所有类可见|所有类可见(默认)|
|private|当前类可见|当前类可见|
|protected|当前类、子类、同一包路径下的类可见|当前类、子类可见|
|default|同一包路径下的类可见(默认)|无|
|internal|无|同一模块中的类可见|


数据类和单例类

MVC、MVVM之类的架构模式种M指的就是数据类,数据类通常需要重写equals()、hashCode()、toString()这几个方法
数据类通常需要重写equals()、hashCode()、toString()这几个方法。其中,equals()方法用于判断两个数据类是否相等。hashCode()方法作为equals()的配套方法,也需要一起重写,否则会导致HashMap、HashSet等hash相关的系统类无法正常工作。toString()方法用于提供更清晰的输入日志,否则一个数据类默认打印出来的就是一行内存地址。
在java中构建数据类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Cellphone { 
String brand;
double price;
public Cellphone(String brand, double price) {
this.brand = brand;
this.price = price;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Cellphone) {
Cellphone other = (Cellphone) obj;
return other.brand.equals(brand) && other.price == price;
}
return false;
}
@Override
public int hashCode() {
return brand.hashCode() + (int) price;
}
@Override
public String toString() {
return "Cellphone(brand=" + brand + ", price=" + price + ")";
}
}

在Kotlin中构建数据类变得极其简单,右击com.example.helloworld 包→New→Kotlin File/Class,在弹出的对话框中输入“Cellphone” ,创建类型选择“Class” 。然后在创建的类中编写如下代码:

1
data class Cellphone(val brand: String, val price: Double) 

当我们希望某个类在全局最多只能拥有一个实例,这时就可以使用单例模式,Java中的写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton { 
private static Singleton instance;
private Singleton() {}
public synchronized static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
public void singletonTest() {
System.out.println("singletonTest is called.");
}
}
//首先为了禁止外部创建Singleton的实例,我们需要用private关键字将Singleton的构造函数私有化,然后给外部提供了一个getInstance()静态方法用于获取Singleton的实例。在getInstance()方法中,我们判断如果当前缓存的Singleton实例为null,就创建一个新的实例,否则直接返回缓存的实例即可,这就是单例模式的工作机制。

在Kotlin中创建一个单例类的方式极其简单,只需要将class关键字改成object关键字即可。现在我们尝试创建一个Kotlin版的Singleton单例类,右击com.example.helloworld 包→New→Kotlin File/Class,在弹出的对话框中输入“Singleton” ,创建类型选择“Object” ,点击“OK”完成创建。