一、内部类和嵌套类
二、密封类:定义受限的类继承结构
sealed修饰符:为父类添加一个sealed修饰符,对可能创建的子类作出严格的限制,所有的直接子类必须嵌套在父类中(Kotlin1.0,可 参考不同kotlin迭代版本中密封类的进化史)。
使用sealed之前创建子类:
interface Expr
class Num(val value:Int):Expr
class Sum(val left:Expr, val right:Expr):Expr
fun eval(e:Expr):Int=
when(e){
is Num -> e.value
is Sum -> eval(e.right) + eval(e.left)
else ->
throw IllegalArgumentException("Unknow expression")
}
}
在上述例子中,如果添加了一个新的子类,但忘记在when中添加一个新分支,编译器会走else,出现潜在的bug。
设置密封类后,可以将else分支去掉:
sealed class Expr{ //注意,此类不是open的,不能被重写
class Num(val value:Int):Expr
class Sum(val left:Expr, val right:Expr):Expr
}
fun eval(e:Expr):Int=
when(e){
is Num -> e.value
is Sum -> eval(e.right) + eval(e.left)
}
}
注意:
Kotlin1.0中,sealed中的所有子类都必须是嵌套的,并且子类不能创建为data类;Kotlin1.1中允许在同一文件的任何位置定义 sealed 类的子类
三、数据类
数据类 和 类委托 可由编译器生成方法。
1、声明数据类
数据类:自动生成通用方法的实现,如自动生成 toString、equals 和 hashCode 方法等。使用 data修饰符 声明数据类:
data class Client(val name:String, val postCode:Int)
注意,equals 和 hashCode 方法会将所有在主构造方法中声明的属性纳入考虑,没有在主构造方法中声明的属性将不会加入到相等性检查和哈希值计算中去。
2、通用对象方法
在 Kotlin 中所有类都有一个共同的超类 Any,Any 类默认提供了三个方法:equal()、hashCode()、toString()。
所以对一个类来说,编译器生成的方法有equals、hashCode 和 toString
(1)toString
//java
public class Test22{
String name;
int postcode;
public Test22(String name, int postcode){
this.name = name;
this.postcode = postcode;
}
@Override
public String toString(){
return "name = " + name + ", postcode = " + postcode;
}
}
class Test33{
public static void main(String args[]){
Test22 test = new Test22("Bob", 789);
System.out.println(test); //注意,这里底层调用了toString
}
}
//Kotlin
class Client(val name:String, val postCode:Int){
override fun toString(): String {
return "name = $name, postCode = $postCode"
}
}
fun main(args:Array<String>){
val client = Client("alice", 123)
println(client)
}
(2)equals
Kotlin与Java不同,在Kotlin中,== 是比较两个对象的默认方式,它本质上是通过调用 equals 来比较两个值的。对 equals 方法进行重写,== 也会起作用。
在Kotlin中,可以使用 === 运算符,来进行引用比较。
class Client(val name:String, val postCode:Int){
override fun equals(other: Any?): Boolean {
if(other == null || other !is Client) return false
return name == other.name && postCode == other.postCode
}
}
fun main(args:Array<String>){
val client = Client("alice", 123)
val client2 = Client("alice", 123)
println("equals:::")
println(client.equals(client2)) //true
println("==:::")
println (client == client2) //true
println("===:::")
println(client === client2) //false
}
(3)hashCode
HashSet中的值在进行比较时,首先比较的是它们的 hash 值,hash 值相等时才会去比较真正的值,所以,比较 HashSet 中的对象的值时,可对该对象所属的类进行hashCode方法的重写,然后再比较。
class Client(val name:String, val postCode:Int){
... ...
override fun hashCode():Int = name.hashCode() * 31 + postCode
}
fun main(args:Array<String>){
val processed = hashSetOf(Client("Alice", 123456))
println(processed.contains(Client("Alice",123456))) //true
}
上述的 Client 类可看做是一个数据容器
3、数据类调用 copy 方法
数据类的属性强烈推荐只适用只读属性,让数据类的实例不可变。
copy方法,允许copy类的实例,并且在copy的同时修改某些属性的值
如:
data class Client(val name:String, val postCode:Int)
fun main(args:Array<String>){
val client = Client("alice", 123)
val copy_client = client.copy(postCode = 789)
println("client:::" + client);
println("copy_client:::" + copy_client)
}
输出结果:
client:::Client(name=alice, postCode=123)
copy_client:::Client(name=alice, postCode=789)
copy()方法已经在创建数据类的时候默认实现了
下面是非数据类中手动实现copy方法,并实现上述代码片段的功能:
class Client(val name:String, val postCode:Int){
fun copy(name:String = this.name,
postCode:Int = this.postCode) = Client(name, postCode)
override fun toString() = "name = $name, postCode = $postCode"
}
fun main(args:Array<String>){
val client = Client("alice", 123)
val copy_client = client.copy(postCode = 789)
println("client:::" + client);
println("copy_client:::" + copy_client)
}
————————————————
版权声明:本文为CSDN博主「浅唱整个春天」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_32677531/article/details/126079614