Kotlin基础知识_01-类_对象
Kotlin基础知识-01-类_对象
1. 创建类并赋值
class Person {
var name = ""
var age = 0
fun eat() {
println(name + " is eating. He is " + age + " years old.")
}
}
fun main() {
val p = Person()
p.name = "Zhang san"
p.age = 20
p.eat()
}
输出:
Zhang san is eating. He is 20 years old.
Note:
name
和age
没有加任何访问修饰符,默认为public
的.
2. 继承、主构造函数、次构造函数、init
2.1 继承
open class Person {
var name = ""
var age = 0
fun eat() {
println(name + " is eating. He is " + age + " years old.")
}
}
class Student : Person() {
var sno = ""
var grade = 0
}
fun main() {
val stu = Student()
stu.name = "Lisi"
stu.age = 10
stu.eat()
}
运行:
Lisi is eating. He is 10 years old.
Note:
- Kotlin中的类(除抽象类外)默认均不可继承,必须手动加上
open
关键字,声明该类可继承。Student : Person()
中,Person后面加了括号,说明调用了父类的无参构造函数;
2.2 主构造函数
class Student(val sno: String, val grade: Int) : Person()
Note:
- Kotlin中的主构造函数是最常用的构造函数,每个类默认都会有一个不带参数的主构造函数,当然也可以显式地给它指明参数,主构造函数直接定义在类名的后面,没有函数体。
2.3 init
如果要在主构造函数中编写逻辑,可使用 init
代码块:
open class Person {
var name = ""
var age = 0
fun eat() {
println(name + " is eating. He is " + age + " years old.")
}
}
class Student(sno: String, grade: Int) : Person() {
init {
println("The sno: $sno")
println("The grade: $grade")
}
}
fun main() {
val stu = Student("A1818", 20)
stu.name = "Lisi"
stu.age = 10
stu.eat()
}
运行:
The sno: A1818
The grade: 20
Lisi is eating. He is 10 years old.
2.4 次构造函数
open class Person(val name: String, val age: Int) {
fun eat() {
println("$name is eating. He is $age years old.")
}
}
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("unknown", 0)
fun info() {
println("sno: $sno, grade is $grade, name: $name, age: $age")
}
}
fun main() {
val stu0 = Student()
stu0.info()
val stu1 = Student("ana", 20)
stu1.info()
val stu2 = Student("A1819", 100, "lil", 20)
stu2.info()
}
运行:
sno: , grade is 0, name: unknown, age: 0
sno: , grade is 0, name: ana, age: 20
sno: A1819, grade is 100, name: lil, age: 20
Note:
- 使用
constructor
关键字来声明次构造函数;- Kotlin规定,当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数(包括间接调用);
- 当在主构造函数中将参数声明成
val
或者var
时,该参数将自动成为该类的字段,如上述的val sno: String, val grade: Int
;- 其中,
name: String, age: Int
不能加上val
或var
关键字,因为这会和父Person中已定义的成员属性冲突。
2.5 只有次构造函数,没有主构造函数
类中只有次构造函数,没有主构造函数。这种情况真的十分少见,但在Kotlin中是允许的。当一个类没有显式地定义主构造函数且定义了次构函数时,它就是没有主构造函数的。
class Boy: Person {
constructor(name: String, age: Int): super(name, age) {}
}
fun main() {
val boy = Boy("zhangSan", 10)
boy.eat()
}
运行:
zhangSan is eating. He is 10 years old.
PS: 这种写法其实没有多大必要性,即使这样写了 IDEA也会报:
Secondary constructor should be converted to a primary one按IDEA的提示转换后,代码会变成:
class Boy(name: String, age: Int) : Person(name, age) { }
3. 接口
3.1 创建接口的方式
interface Hobby {
fun sing()
fun jump()
fun rap() {
println("I'm rapping....")
}
}
Note:接口中的函数可以有函数体也可以没有,没有函数体的话在继承时需要强制实现,有函数体的话,则不需要强制实现。
3.2 实现接口
class Boy(name: String, age: Int) : Person(name, age), Hobby, Sport {
override fun sing() {
println("$name like sing.")
}
override fun jump() {
println("$name like jump.")
}
override fun playBall() {
println("$name like play ball.")
}
}
interface Sport {
fun playBall()
}
interface Hobby {
fun sing()
fun jump()
fun rap() {
println("I'm rapping....")
}
}
fun main() {
val boy = Boy("zhangSan", 10)
boy.sing()
boy.jump()
boy.rap()
boy.playBall()
}
运行:
zhangSan like sing.
zhangSan like jump.
I'm rapping....
zhangSan like play ball.
Note:
- 实现接口直接使用
:
号连接即可,不要使用implements
关键字, kotlin中继承父类和实现接口均使用:
符号;- 可以实现多个接口,多个接口间用
,
号分隔;- 实现接口不需要给接口名加上
()
, 因为接口没有构造函数。- kotlin 使用
override
关键字来重写父类或接口中的函数。
4. 访问修饰符 - public, private, protected, internal
与 java 中 默认的4种访问修饰符区别:
修饰符 | Java | Kotlin |
---|---|---|
public | 所有类可见 | 所有类可见(默认) |
private | 当前类可见 | 当前类可见 |
protected | 当前类、子类、同一包路径下的类可见 | 当前类、子类可见 |
default | 同一包路径下的类可见(默认) | 没有 |
internal | 没有 | 同一模块中的类可见 |
Note: 主要有以下区别:
- java 默认访问修饰符若不写则为包级的,kotlin 默认为 public的;
- kotlin中的protected 访问修饰符缩小了作用范围,只在当前类和子类中可见;
- kotlin中新引入了一个
internal
访问修饰符,用于模块内可见。比如我们开发了一个lib给别人使用,但是有一些函数只允许在lib内部调用,不想给外部使用,就可以将这些函数声明成internal。
5. 数据类和单例类
5.1 数据类(data class)
数据类也叫实体类,java 里面就是一个domain对象,一般这样定义:
public class Man {
private String mName;
private int mAge;
private String mAddress;
public String getName() {
return mName;
}
public void setName(String mName) {
this.mName = mName;
}
public int getAge() {
return mAge;
}
public void setAge(int mAge) {
this.mAge = mAge;
}
public String getAddress() {
return mAddress;
}
public void setAddress(String mAddress) {
this.mAddress = mAddress;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Man man = (Man) o;
return mAge == man.mAge && Objects.equals(mName, man.mName) && Objects.equals(mAddress, man.mAddress);
}
@Override
public int hashCode() {
return Objects.hash(mName, mAge, mAddress);
}
@Override
public String toString() {
return "Man{" +
"mName='" + mName + '\'' +
", mAge=" + mAge +
", mAddress='" + mAddress + '\'' +
'}';
}
}
一般都要实现 getter/setter 方法 ,如果需要对两个对象进行比较,还需要实现 equals()、hashCode()、toString()
等方法。
kotlin中实现:
data class Man(val name: String, val age: Int, val address: String)
fun main() {
val man1 = Man("Li", 20, "Beijing")
println("[man1], name: ${man1.name}, age: ${man1.age}, address: ${man1.address}")
val man2 = Man("Li", 20, "Beijing")
println("[man2], name: ${man2.name}, age: ${man2.age}, address: ${man2.address}")
println("man1 == man2: ${man1 == man2}")
}
运行:
[man1], name: Li, age: 20, address: Beijing
[man2], name: Li, age: 20, address: Beijing
man1 == man2: true
只要使用 data
关键字声明就可以,该类会自动成为数据类,且自动带 getter/setter 方法, 自动实现 equals()、hashCode()、toString()
等固定且无实际逻辑意义的方法。
Note: 当一个类中没有任何代码时,还可以将尾部的大括号省略。上面的数据类就没有带大括号。
5.2 单例
java 单例:
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.");
}
}
一般单例如上述写法(注意,不严谨,最好用双重检查锁的方式)。
kotlin 单例:
object Singleton {
fun singletonTest() {
println("singletonTest is called.")
}
}
fun main() {
Singleton.singletonTest()
}
运行:
singletonTest is called.
Note: 只要用
object
关键字声明即可,kotlin 保证该类的对象在JVM中是唯一的。