一、嵌套类
如果一个类只对另一个类有用,那么将其嵌入到该类中并使这两个类保持在一起是合乎逻辑的,可以使用
class Player2 { /** * 嵌套类 * 如果一个类只对另一个类有用,那么将其嵌入到该类中并使这两个类保持在一起是合乎逻辑的,可以使用 * 嵌套类。 */ class Equipment(var name: String) { fun show() = println("equipment:$name") } fun battle() { } } fun main() { Player2.Equipment("sharp knife").show() }
输出结果如下
equipment:sharp knife
二、数据类
/** * 数据类 * 数据类,是专门设计用来存储数据的类 * 数据类提供了toString的个性化实现 * ==符号默认情况下,比较对象就是比较它们的引用值,数据类提供了equals和hashCode * 的个性化实现。 */ data class Coordinate(var x: Int, var y: Int, val z: Int) { val isInBounds = x > 0 && y > 0 } fun main() { println(Coordinate(10, 20, 30)) //== 比较的是内容 equals 默认使用的超类Any的实现 === 比较的是引用 // === 比较的是对象的引用 println(Coordinate(10, 20, 30) == Coordinate(10, 20, 30)) val (x, y, z) = Coordinate(10, 20, 30) println("$x,$y,$z") }
输出结果如下
Coordinate(x=10, y=20, z=30) true 10,20,30
三、数据类中的copy函数
data class Student(var name: String, val age: Int) { private val hobby = "music" val subject: String var score = 0 init { println("initializing student") subject = "math" } constructor(_name: String) : this(_name, 10) { score = 10 } override fun toString(): String { return "Student(name='$name', age=$age, hobby='$hobby', subject='$subject', score=$score)" } } fun main() { val student = Student("jack") /** * copy * 除了重写Any类的部分函数,提供更好用的默认实现外,数据类还提供了一个函数,它可以用来 * 方便地复制一个对象。假设你想创建一个Student实例,除了name属性,它拥有和另一个现有Student实例完全一样 * 的属性值,如果Student是个数据类,那么复制现有Student实例就很简单了,只要调用copy函数,给想修改的属性 * 传入值参就可以了。 */ var copyStudent = student.copy("Rose") println(student) println(copyStudent) }
输出结果如下
initializing student initializing student Student(name='jack', age=10, hobby='music', subject='math', score=10) Student(name='Rose', age=10, hobby='music', subject='math', score=0)
四、数据类中的解构声明
class PlayerScore(val experience: Int, val level: Int) { /** * 解构声明 * 解构声明的后台实现就是component1、component2等若干个组件函数 * 让每个函数负责管理你想返回的一个属性数据,如果你定义一个数据类, * 它会自动为所有定义在主构造函数的属性添加对应的组件函数。 */ operator fun component1() = experience operator fun component2() = level } fun main() { val (x, y) = PlayerScore(10, 20) println("$x $y") }
输出结果如下
10 20
创建一个数据类看一下效果
data class Coordinate(var x: Int, var y: Int, val z: Int) { val isInBounds = x > 0 && y > 0 } fun main() { println(Coordinate(10, 20, 30)) //== 比较的是内容 equals 默认使用的超类Any的实现 === 比较的是引用 // === 比较的是对象的引用 println(Coordinate(10, 20, 30) == Coordinate(10, 20, 30)) val (x, y, z) = Coordinate(10, 20, 30) println("$x,$y,$z") }
输出结果
Coordinate(x=10, y=20, z=30) true 10,20,30
五、数据类中的运算符重载
data class Coordinate2(var x: Int, var y: Int) { val isInBounds = x > 0 && y > 0 /** * 运算符重载 * 如果要将内置运算符应用在自定义类身上,你必须重写运算符函数,告诉编译器该如何操作自定义类。 */ /** * plus函数名 对应的操作符为+ * 把一个对象添加到另一个对象里。 */ operator fun plus(other: Coordinate2) = Coordinate2(x + other.x, y + other.y) } fun main() { val c1 = Coordinate2(10, 20) val c2 = Coordinate2(10, 20) println(c1 + c2) }
输出结果如下
Coordinate2(x=20, y=40)
使用数据类的条件
正是因为上述这些特性,你才倾向于用数据类来表示存储数据的简单对象,对于那些经常需要比较,复制或打印自身内容的类,数据类尤其适合它们。然而,一个类要成为数据类,也要符合一定条件。总结下来,主要有三个方面
1.数据类必须有至少带一个参数的主构造函数
2.数据类主构造函数的参数必须是var或者val
3.数据类不能使用abstract、open、sealed和inner修饰符。
六、枚举类
/** * 枚举类 * 枚举类,用来定义常量集合的一种特殊类。 */ enum class Direction { EAST, WEST, SOUTH, NORTH } fun main() { println(Direction.EAST) println(Direction.EAST is Direction) } • 15
输出结果如下
EAST true
七、枚举类中定义函数
/** * 枚举类 * 枚举类,用来定义常量集合的一种特殊类。 */ enum class Direction2(private val coordinate2: Coordinate2) { EAST(Coordinate2(10, 20)), WEST(Coordinate2(11, 21)), SOUTH(Coordinate2(12, 22)), NORTH(Coordinate2(13, 23)); /** * 枚举类也可以定义函数 */ fun updateCoordinate2(playerCoordinate: Coordinate2) = Coordinate2(playerCoordinate.x + coordinate2.x, playerCoordinate.y + coordinate2.y) } fun main() { println(Direction2.EAST.updateCoordinate2(Coordinate2(10, 20))) }
输出结果
Coordinate2(x=20, y=40)
八、代数数据类型
/** * 代数数据类型 * 可以用来表示一组子类型的闭集,枚举类就是一种简单的ADT(抽象数据类型) */ enum class LicenseStatus { UNQUALIFIED, LEARNING, QUALIFIED; } class Driver(var status: LicenseStatus) { fun checkLicense(): String { return when (status) { LicenseStatus.UNQUALIFIED -> "没资格" LicenseStatus.LEARNING -> "在学" LicenseStatus.QUALIFIED -> "有资格" } } } fun main() { println(Driver(LicenseStatus.QUALIFIED).checkLicense()) }
输出结果如下
有资格
九、密封类的详解
/** * 密封类 * 对于更复杂的ADT(抽象数据类型),你可以使用kotlin的密封类(sealed class)来实现更复杂的定义 * 密封类可以用来定义一个类似于枚举类的ADT,但你可以更灵活地控制某个子类型。 * 密封类可以有若干个子类,要继承密封类,这些子类必须和它定义在同一个文件里。 */ sealed class LicenseStatus2 { object UNQUALIFIED : LicenseStatus2() object LEARNING : LicenseStatus2() class QUALIFIED(val licenseId: String) : LicenseStatus2() } class Driver2(var status: LicenseStatus2) { fun checkLicense(): String { return when (status) { is LicenseStatus2.UNQUALIFIED -> "没资格" is LicenseStatus2.LEARNING -> "在学" is LicenseStatus2.QUALIFIED -> "有资格,驾驶证编号:${(this.status as LicenseStatus2.QUALIFIED).licenseId}" } } } fun main() { val status = LicenseStatus2.LEARNING val driver2 = Driver2(status) println(driver2.checkLicense()) val status1 = LicenseStatus2.QUALIFIED("809987") val driver = Driver2(status1) println(driver.checkLicense()) }
输出结果如下
在学 有资格,驾驶证编号:809987