1 类的定义
1.1 类的定义
//Java
public class Person {
}
复制代码
//Kotlin
class Person
复制代码
类的定义中,Kotlin与Java对比有以下异同(假设读者熟知Java):
同
- 都使用
class
关键字; - 都使用
{}
大括号包裹类的body;
异
- Kotlin默认为
public
,省略不写为public
,可以加上private
和protected
修饰; - 若类无body,则可以省略掉
{}
不写;
1.2 属性定义
//Java
public class Person {
public String name;
public int age;
}
复制代码
//Kotlin
class Person {
var name: String = ""
var age: Int = 0
}
复制代码
Java中,类中定义的变量称为字段(Field);Kotlin中,类中定义的变量称为属性(Property)。需要注意的是,Kotlin中的所有的属性在定义的时候都必须手动初始化(或指明初始化的时机),否则报错;而Java中的字段不手动初始化都会具有默认的初始值。
1.3 函数(方法)定义
//Java
public class Person {
public String name;
public int age;
public void introduceSelf() {
System.out.println("Hello! I am " + name + ", and I am " + age + "years old.");
}
}
复制代码
//Kotlin
class Person {
var name: String = ""
var age: Int = 0
fun introduceSelf() {
println("Hello! I am $name and I am $age years old.")
}
}
复制代码
Kotlin类中函数(方法)的定义与普通函数的定义没有区别,使用fun
关键字,接函数(方法)名,接:
冒号,接返回值类型,接{}
包裹的函数体即可,:Unit
可以省略不写,详见《Java转Kotlin:函数基础》。
1.4 构造器定义
//Java
public class Person {
public String name;
public int age;
Person(name, age) {
this.name = name;
this.age = age;
};
}
复制代码
//Kotlin
class Person(var name: String, var age: Int) {
}
复制代码
Kotlin中有主构造器与副构造器的区别,并且规定:所有的副构造器必须调用主构造器。像上面直接写在类名后面的就是主构造器。
2 接口的定义
2.1 接口的定义
//Java
public interface Act {
void introduceSelf();
void walk();
}
复制代码
//Kotlin
interface Act {
fun introduceSelf()
fun walk()
}
复制代码
2.2 接口的实现
//Java
public Person implements Act {
@Override
void introduceSelf() {
//TODO
}
@Override
void walk() {
//TODO
}
}
复制代码
//Kotlin
class Person(var name: String, var age: Int) : Act {
override fun introduceSelf() {
//TODO
}
override fun walk() {
//TODO
}
}
复制代码
Java中的接口实现使用implements
关键字;
Kotlin中的接口实现使用:
;
Java中的接口实现使用@Override
注解,起到提示性作用;
Kotlin中接口实现必须使用override
关键字,是强制性的。
3 抽象类的定义
3.1 抽象类的定义
//Java
abstract class Person implements Act {
public String name;
public int age;
public String job;
public Person(String name, int age, String job) {
this.name = name;
this.age = age;
this.job = job;
}
public abstract void think();
public void learn() {}
public void talk() {}
}
复制代码
//Kotlin
abstract class Person(var name: String, var age: Int, var job: String) : Act {
abstract fun think()
fun learn() {}
open fun talk() {}
}
复制代码
3.2 抽象类的实现
//Java
public Teacher extends Person {
public Teacher(String name, int age, String job) {
super(name, age, job);
}
@Override
public void think() {
System.out.println("Teacher" + this.name + "is thinking.");
}
@Override
public void learn() {
System.out.println("Teacher" + this.name + "is learning.");
}
@Override
public void talk() {
System.out.println("Teacher" + this.name + "is talking.");
}
}
复制代码
//Kotlin
abstract class Person(var name: String, var age: Int, var job: String) : Act {
abstract fun think()
fun learn() {}
open fun talk() {}
}
open class Teacher(name: String, age: Int, job: String, var grade: Int) : Person(name, age, job) {
override fun introduceSelf() {
println("Hello! My name is $name. I'm a $job, I teach grade $grade and I'm $age years old.")
}
override fun walk() {
println("Teacher $name is walking.")
}
override fun think() {
println("Teacher $name is thinking.")
}
override fun talk() {
println("Teacher $name is talking.")
}
}
复制代码
注意
open
关键字:在Kotlin中,若子类想要重写父类的方法,则要求父类的方法被open
关键字修饰;若子类重写了父类的方法之后,不希望自己的子类再重写该方法,则可用final
关键字,拒绝子类重写方法,如果没有final
关键字,open
关键字的属性将得以传递。即在类里面定义方法时,默认是final
的。
上图中的learn()
方法没有open
关键字,所以子类Tearcher
无法重写该方法。
4 重要知识点
4.1 属性与字段
Java定义在类中的变量都被称为字段(Field);
Kotlin定义在类中的var
或val
都被称为属性(Property)。
二者有什么区别呢?
Property = Field + Setter + Getter
例如,我们在接口中定义一个属性:
//Kotlin
interface Act {
var actCount: Int
fun introduceSelf()
fun walk()
}
复制代码
实现该接口的类要么是抽象类,要么需要实现该属性的set()
与get()
方法:
//Kotlin
open class Teacher(name: String, age: Int, job: String, var grade: Int) : Person(name, age, job) {
override fun think() {
println("Teacher $name is thinking.")
}
override fun introduceSelf() {
println("Hello! My name is $name. I'm a $job, I teach grade $grade and I'm $age years old.")
}
override fun walk() {
println("Teacher $name is walking.")
}
override fun talk() {
println("Teacher $name is talking.")
}
override var actCount: Int = 2
get() {
return field
}
set(value) {
field = value
}
}
复制代码
代码中的field
在IDE中被加粗显示,这个field
被称为backing field,称为幕后字段,因此,可以说明属性Property与字段Field的关系。
4.2 属性引用
//Kotlin
package imooc.chapter_4
//TODO:定义一个接口
interface Act {
var actCount: Int
fun introduceSelf()
fun walk()
}
//TODO:定义一个类
abstract class Person(var name: String, var age: Int, var job: String) : Act {
abstract fun think()
fun learn() {}
open fun talk() {}
}
open class Teacher(name: String, age: Int, job: String, var grade: Int) : Person(name, age, job) {
override fun think() {
println("Teacher $name is thinking.")
}
override fun introduceSelf() {
println("Hello! My name is $name. I'm a $job, I teach grade $grade and I'm $age years old.")
}
override fun walk() {
println("Teacher $name is walking.")
}
override fun talk() {
println("Teacher $name is talking.")
}
override var actCount: Int = 4
get() {
return field
}
set(value) {
field = value
}
}
open class Policeman(name: String, age: Int, job: String, var cases: Int) : Person(name, age, job) {
override fun think() {
println("Teacher $name is thinking.")
}
override var actCount: Int = 3
get() = field
set(value) {
field = value
}
override fun introduceSelf() {
println("Hello! My name is $name. I'm a $job, I've solved $cases cases and I'm $age years old.")
}
override fun walk() {
println("Policeman $name is walking.")
}
}
fun main() {
val mike = Policeman("Mike", 23, "Policeman", 56)
mike.introduceSelf()
mike.walk()
//TODO:属性引用
val actCountRef1 = Policeman::actCount
actCountRef1.set(mike, 3)//actCountRef1未绑定Receiver,因此需要传递一个Receiver进来
val actCountRef2 = mike::actCount
actCountRef2.get()//actCountRef2绑定了Receiver mike,因此不需要传递Receiver进来
}
复制代码
我们着重看一下main()
函数,注意属性引用的部分,这与Java的反射有相似的味道。