一、枚举类
枚举类,用来界说常量调集的一种特殊类。运用 enum class 能够声明一个枚举类。
1.1 创立枚举类
枚举常量用逗号分隔,每个枚举常量都是一个目标
enum class Color{
RED,
BULE,
YELLOW
}
fun main() {
//运用
println(Color.RED)
}
1.2 获取枚举相关信息
val name: String //获取枚举称号,,默许称号为枚举字符名
val ordinal: Int //获取枚举值在一切枚举数组中界说的次序,值从 0 开端
fun main() {
//运用
val blue = Color.BULE
println(blue.name)
println(blue.ordinal)
}
1.3 枚举类增加特点
每一个枚举都是枚举类的实例,它们能够被初始化。
若需求指定值,则能够运用其结构函数。
//2.0版别
enum class Color2(val user: UserColor) {
RED(UserColor("小红", 15)),
BULE(UserColor("小蓝", 20)),
YELLOW(UserColor("小黄", 30));
}
data class UserColor(val name: String, val age: Int)
fun main() {
//2.0版别
println(Color2.BULE.user)
}
1.4 界说函数
enum class Color2(val user: UserColor) {
...
RED(UserColor("小红", 15));
fun addUser(adduser:UserColor)=
UserColor("${adduser.name}-${user.name}"
,adduser.age+user.age)
}
fun main() {
//枚举界说函数
println(Color2.RED.addUser(UserColor("新", 40)))
}
1.5 以泛型的办法拜访枚举类中的常量
自 Kotlin 1.1 起,能够运用 enumValues<T>()
和enumValueOf<T>()
函数以泛型的办法拜访枚举类中的常量
@SinceKotlin("1.1")
public inline fun <reified T : Enum<T>> enumValues(): Array<T>
/**
* Returns an enum entry with specified name.
*/
@SinceKotlin("1.1")
public inline fun <reified T : Enum<T>> enumValueOf(name: String): T
//运用
fun main() {
println(enumValueOf<Color>("RED"))
println(enumValues<Color2>().joinToString { it.user.toString() })
}
1.6 代数数据类型(ADT)
能够用来表示一组子类型的闭集,枚举类便是一种简单的ADT。
运用枚举的要害好处在于运用 when 表达式的时分,假如能够 验证句子掩盖了一切状况,就不需求为该句子再增加一个 else 子句了。
enum class ColorADT {
RED,
BULE,
YELLOW
}
class TakeColor(var colorADT: ColorADT) {
fun selectColor(): String {
return when (colorADT) {
ColorADT.RED -> "赤色"
ColorADT.BULE -> "蓝色"
ColorADT.YELLOW -> "黄色"
// 不再需求 `else` 子句,由于咱们现已掩盖了一切的状况
}
}
}
fun main() {
println(TakeColor(ColorADT.BULE).selectColor())
}
但是假如咱们想在返回是赤色的时分给一个提示。假如运用枚举类,那么还需求判断就有一些杂乱了。关于更杂乱的ADT,你能够运用Kotlin的密封类(sealed class)来实现更杂乱的界说。
二、密封类(sealed class)
-
关于更杂乱的ADT,你能够运用Kotlin的密封类(sealed class)来实现更杂乱的界说,密封类能够用来界说一个相似于枚举类的ADT,但你能够更灵活地操控某个子类型。
-
密封类能够有若干个子类,要承继密封类,这些子类有必要和它界说在同一个文件里。
-
sealed 要害字不能润饰 interface ,abstract class(会报 warning,但是不会出现编译过错)
2.1 创立密封类
sealed class ColorSealed{
//以下都是密封类的子类
//运用object用的是单例,由于下面两个子类没有特点,不论生成多少次都相同
object Blue : ColorSealed()
object Yellow : ColorSealed()
//这个子类有特点,或许特点不同,所以要生成不同的目标
class Red(val toast:String) : ColorSealed()
}
2.2 运用
运用密封类的要害好处在于运用 when 表达式的时分,假如能够 验证句子掩盖了一切状况,就不需求为该句子再增加一个 else 子句了。
class TakeColorSealed(var colorSealed: ColorSealed) {
fun selectColor(): String {
return when (colorSealed) {
is ColorSealed.Blue -> "蓝色"
is ColorSealed.Yellow -> "黄色"
is ColorSealed.Red ->
"赤色,${(this.colorSealed as ColorSealed.Red).toast}"
//不再需求 else 子句,由于咱们现已掩盖了一切的状况
}
}
}
fun main() {
println(TakeColorSealed(ColorSealed.Blue).selectColor())
println("----------")
println(TakeColorSealed(ColorSealed.Red("正告正告!!!")).selectColor())
}
这儿跟枚举类的运用不太相同。用到了 is 要害字。
调用赤色提示的时分将当前的ColorSealed转化为ColorSealed.Red,由于编译时也不知道你传入的是Red还是其他的。
三、数据类
运用 data class 要害字创立一个只包括数据的类,这种类又称数据类。这个是Kotlin独有的,Java没有数据类。
编译器会自动的从主结构函数中根据一切声明的特点提取以下函数:
-
生成 equals() 函数与 hasCode() 函数
-
生成 toString() 函数,由类名(参数1 = 值1,参数2 = 值2,….) 构成
-
由所界说的特点自动生成component1()、component2()、…、componentN()函数,其对应于特点的声明次序。
-
copy() 函数
数据类需求满意以下条件:
-
主结构函数至少包括一个参数。
-
一切的主结构函数的参数有必要标识为val或许var。
-
数据类不能够声明为abstract,open,sealed或许inner。
-
数据类不能承继其他类 (但是能够实现接口)。
data class DaTang (var name:String ,val age:Int)
在没有结构体的时分,大括号{}可省略。
3.1 创立数据类
data class DaTang (var name:String ,val age:Int){
val emperor = "$name,是继隋朝之后的大一统华夏王朝,共历二十一帝,享国-$age-年。"
}
fun main() {
println(DaTang("唐朝", 289))
}
假如不运用 data class 要害字润饰,而运用class要害字润饰,如下:
3.2 toString、equals和hashCode的个性化实现
3.3 ==符号
data class DaTang (var name:String ,val age:Int){
val emperor = "$name,是继隋朝之后的大一统华夏王朝,共历二十一帝,享国-$age-年。"
}
class DaTang2 (var name:String ,val age:Int){
val emperor = "$name,是继隋朝之后的大一统华夏王朝,共历二十一帝,享国-$age-年。"
}
fun main() {
println(DaTang("唐朝", 289))
// "==“比较的是内容 equals(Any)。
// 因未重写Any的equals函数,运用的是Any默许equals函数,所以比较的还是引证。
// "===" 比较的是引证(类所占的内存区域)
println(DaTang2("唐朝", 289) == DaTang2("唐朝", 289))
//这儿运用的是data class,数据类重写了equals,比较的是数据类里面的数据。
println(DaTang("唐朝", 289) == DaTang("唐朝", 289))
}
3.4 copy() 函数
copy() 函数应该是相似Java中的clone() 办法
data class DaTang (var name:String ,val age:Int){
val emperor = "$name,是继隋朝之后的大一统华夏王朝,共历二十一帝,享国-$age-年。"
}
fun main() {
val datang = DaTang("唐朝", 289)
println(datang)//DaTang(name=唐朝, age=289)
//创立了了一个新的目标
val diguo = datang.copy(age=500)
println(diguo)//DaTang(name=唐朝, age=500)
}
3.5 解构声明
数据类:由所界说的特点自动生成component1()、component2()、…、componentN()函数,其对应于特点的声明次序。
一般类:运用 operator 要害字界说component1()、component2()、…、componentN()函数。
data class DataDaSong(var name:String ,var age:Int)
class DaSong(var name:String ,var age:Int){
//解构语法:有必要从component1开端
operator fun component1() = name
operator fun component2() = age
}
fun main() {
//运用一般类需求自己写component1、component2...componentN
var (name,age) = DaSong("北宋",167)
println("$name,是我国历史上继五代十国之后的朝代,传九位皇帝,享国-$age-年")
//运用数据类支撑解构语法,自动生成operator fun component1
var (dataname,dataage) = DataDaSong("北宋",167)
println("数据类:$dataname,是我国历史上继五代十国之后的朝代,传九位皇帝,享国-$dataage-年")
}
查看数据类反编译代码:
四、 承继(extend)
Kotlin 答应一个类承继自另一个类
Kotlin 中一切类都承继自 Any 类
Any 类是一切类的超类,关于没有超类型声明的类是默许超类
Kotlin 类默许都是关闭的,要让某个类敞开承继,有必要运用 open 要害字润饰它。
留意:
在 Kotlin 中 Any 类是一切类的超类
在 Java 中 Object 类是一切类的超类
4.1 Any 超类
Any 默许提供了三个函数:
public open class Any {
public open operator fun equals(other: Any?): Boolean
public open fun hashCode(): Int
public open fun toString(): String
}
从这儿发现 无论是类还是函数,都运用了 open 要害字润饰。
一起发现,这儿仅仅界说了函数,没有实现。为什么呢?由于Kotlin是跨渠道语言,能够在Android、macOS、Windows、JavaScript上运行,为了支撑跨渠道更友爱,在不同渠道有不同实现,所以在这儿并未展示。
4.2 承继类
/* 食物基类 */
open class Food{
fun explain() = "Food explain"
}
class Apple :Food(){
}
不加 open 要害字润饰是不让承继滴,如下图:
4.3 函数重写
在基类中,运用 fun 声明函数时,此函数默许为 final 润饰,不能被子类重写。
假如答应子类重写该函数,那么有必要运用 open 要害字润饰它, 子类重写函数运用 override 要害字。
/* 食物基类 */
open class Food{
//函数有必要用 open 要害字润饰,子类才干掩盖
open fun explain() = "Food explain"
}
/* 承继Food */
class Apple :Food(){
//运用 override 要害字掩盖父类函数
override fun explain() = "Apple explain "
}
在 Kotlin 中 override 是个要害字而不是注解。
运用
fun main() {
//多态:父类类型的引证子类类型的目标
val f: Food = Apple()
println(f.explain())
}
4.4 特点重写
/* 食物基类 */
open class Food {
open val price = 100
...
}
/* 承继Food */
class Apple : Food() {
override var price = 36
...
}
fun main() {
//多态:父类类型的引证子类类型的目标
val f: Food = Apple()
println(f.explain())//Apple explain 36
}
4.5 类型检测(is
)
Kotlin的 is运算符 能够用来查看某个目标的类型。
println(f is Food)//true
println(f is Apple)//true
println(f is File)//false
智能类型转化(as
)
Kotlin的 as运算符 能够用对某个目标进行类型转化。
智能安全转化操作符:as?
as?安全地转化成一种类型。 假如无法进行转化,则返回null,而不是抛出ClassCastException反常。
咱就在上面的实例基础上修正。
var asTest :String? = ""
//不安全的转化操作符 as
// println(asTest as Int)//ClassCastException
//安全的转化操作符 as?
println(asTest as? Int)//null