在前面几个章节章节中,详细的讲解了Koltin
中的接口类(Interface)
、枚举类(Enmu)
,还不甚了解的可以查看我的上一篇文章Kotlin——中级篇(五):枚举类(Enum)、接口类(Interface)详解。当然,在Koltin
中,除了接口类、枚举类
之外,还有抽象类、内部类、数据类
以及密封类
。在今天的章节中,为大家详细讲解数据类
和密封类
。在下一章节中,再为大家奉上Kotlin
中的抽象类
以及内部类
的知识。如果还对Kotlin
中类
的分类还不清楚的可以查看我的另一篇博文Kotlin——中级篇(一):类(class)详解。
目录
一、数据类
1、关键字
1.1、声明格式
data class 类名(var param1 :数据类型,...){}
或者
data class 类名 可见性修饰符 constructor(var param1 : 数据类型 = 默认值,...)
说明:
例:
// 定义一个名为Person的数据类
data class Preson(var name : String,val sex : Int, var age : Int)
1.2、约定俗成的规定
即,当构造函数中的参过多时,为了代码的阅读性,一个参数的定义占据一行。
例:
data class Person(var param1: String = "param1",
var param2: String = "param2",
var param3 : String,
var param4 : Long,
var param5 : Int = 2,
var param6 : String,
var param7 : Float = 3.14f,
var param8 : Int,
var param9 : String){
// exp
.
.
.
}
1.3、编辑器为我们做的事情
当我们声明一个数据类
时,编辑器自动为这个类做了一些事情,不然它怎么又比Java
简洁呢。它会根据主构造函数中所定义的所有属性自动生成下列方法:
其中,当这些函数中的任何一个在类体中显式定义或继承自其基类型,则不会生成该函数
2、数据类的特性
数据类
有着和Kotlin
其他类不一样的特性。除了含有其他类的一些特性外,还有着其独特的特点。并且也是数据类
必须满足的条件:
3、用实例说明其比Java
的简洁性
3.1、数据类的对比
Kotlin版:
data class User(val name : String, val pwd : String)
Java版:
public class User {
private String name;
private String pwd;
public User(){}
public User(String name, String pwd) {
this.name = name;
this.pwd = pwd;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
分析:实现同一个功能,从代码量来说,Koltin
比Java
少了很多行代码,比起更简洁。
3.2、修改数据类属性
例:修改User
类的name
属性
Kotlin版:
val mUser = User("kotlin","123456")
println(mUser)
val mNewUser = mUser.copy(name = "new Kotlin")
println(mNewUser)
输出结果为:
User(name=kotlin, pwd=123456)
User(name=new Kotlin, pwd=123456)
Java版:
User mUser = new User("Java","123456");
System.out.println(mUser);
mUser.setName("new Java");
System.out.println(mUser);
输出结果为:
User{name='Java', pwd='123456'}
User{name='new Java', pwd='123456'}
分析:从上面对两种方式的实现中可以看出,Kotlin
是使用其独有的copy()
函数去修改属性值,而Java
是使用setXXX()
去修改
4、解构声明
val mUser = User("kotlin","123456")
val (name,pwd) = mUser
println("name = $name\tpwd = $pwd")
输出结果为:
name = kotlin pwd = 123456
5、系统标准库中的标准数据类
5.1、源码分析
@file:kotlin.jvm.JvmName("TuplesKt")
package kotlin
// 这里去掉了源码中的注释
public data class Pair<out A, out B>(
public val first: A,
public val second: B) : Serializable {
// toString()方法
public override fun toString(): String = "($first, $second)"
}
// 转换
public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
// 转换成List集合
public fun <T> Pair<T, T>.toList(): List<T> = listOf(first, second)
// 这里去掉了源码中的注释
public data class Triple<out A, out B, out C>(
public val first: A,
public val second: B,
public val third: C ) : Serializable {
// toString()方法
public override fun toString(): String = "($first, $second, $third)"
}
// 转换成List集合
public fun <T> Triple<T, T, T>.toList(): List<T> = listOf(first, second, third)
分析:从上面的源码可以看出,标准库中提供了两个标准的数据类,Pair类
以及Triple类
.其中:
5.2、用法
val pair = Pair(1,2) // 实例
val triple = Triple(1,2,3) // 实例
println("$pair \t $triple") // 打印:即调用了各自的toString()方法
println(pair.toList()) // 转换成List集合
println(triple.toList()) // 转换成List集合
println(pair.to(3)) // Pair类特有: 其作用是把参数Pair类中的第二个参数替换
输出结果为:
(1, 2) (1, 2, 3)
[1, 2]
[1, 2, 3]
((1, 2), 3)
二、密封类
1、什么是受限的类继承结构
上面的几点内容是密封类的特点,请详细的看下去,小生会对这几点内容进行详细的分析。
2、关键字
2.1、声明格式
sealed class SealedExpr()
即
val mSealedExpr = SealedExpr() // 这段代码是错误的,编译器直接会报错不能编译通过。
既然密封类
是不能实例化,那么我们要怎么使用,或者说它的作用是什么呢?请继续往下看
3、密封类的作用及其详细用法。
3.1、作用
例:
sealed class SealedExpr{
data class Person(val num1 : Int, val num2 : Int) : SealedExpr()
object Add : SealedExpr() // 单例模式
object Minus : SealedExpr() // 单例模式
}
// 其子类可以定在密封类外部,但是必须在同一文件中 v1.1之前只能定义在密封类内部
object NotANumber : SealedExpr()
分析:即所定义的子类都必须继承于密封类,表示一组受限的类
3.2、和普通继承类的区别
3.3、和枚举类的区别
例:
val mPerson1 = SealedExpr.Person("name1",22)
println(mPerson1)
val mPerson2 = SealedExpr.Person("name2",23)
println(mPerson2)
println(mPerson1.hashCode())
println(mPerson2.hashCode())
输出结果为:
Person(name=name1, age=22)
Person(name=name2, age=23)
-1052833328
-1052833296
3.4、其子类的类扩展实例
为了演示密封类的子类的扩展是可以在项目中的任何位置这个功能,大家可以下载源码。源码链接在文章末尾会为大家奉上。
例:
// 其存在于SealedClassDemo.kt文件中
sealed class SealedExpr{
data class Person(val name : String, val age : Int) : SealedExpr()
object Add : SealedExpr()
companion object Minus : SealedExpr()
}
object NotANumber : SealedExpr()
其存在TestSealedDemo.kt文件中
fun <T>SealedExpr.Add.add(num1 : T, num2 : T) : Int{
return 100
}
fun main(args: Array<String>) {
println(SealedExpr.Add.add(1,2))
}
输出结果为:
100
3.5、使用密封类的好处
例:
sealed class SealedExpr{
data class Person(val name : String, val age : Int) : SealedExpr()
object Add : SealedExpr()
companion object Minus : SealedExpr()
}
object NotANumber : SealedExpr()
fun eval(expr: SealedExpr) = when(expr){
is SealedExpr.Add -> println("is Add")
is SealedExpr.Minus -> println("is Minus")
is SealedExpr.Person -> println(SealedExpr.Person("Koltin",22))
NotANumber -> Double.NaN
}
输出结果为:
is Minus
三、总结
在实际的项目开发当中,数据类(data
)类的用处是很多的,因为在开发APP
时,往往会根据后台开发者所提供的接口返回的json
而生成一个实体类,现在我们学习了数据类后,就不用再像Java
一样写那么多代码了,即使是用编辑器提供的方法去自动生成。但是代码量上就能节省我们很多时间,并且也更加简洁。何乐而不为呢!密封类的情况在实际开发中不是很常见的。只有当时特殊的需求会用到的时候,才会使用密封类。当然我们还是要学习的。
如果各位大佬看了之后感觉还阔以,就请各位大佬随便star
一下,您的关注是我最大的动力。
我的个人博客:Jetictors
我的github:Jetictors
我的掘金:Jetictors