1.继承
默认情况下,Kotlin 类是最终(final)的——它们不能被继承。 要使一个类可继承,请用 open 关键字标记它:
open class Base(p: Int)
class Derived(p: Int) : Base(p)
open class product(val name : String) {
open fun description() = "Product: $name"
fun load() = "nothing.."
}
class LuxuryProduct(name: String) : product(name) {
override fun description() = "Luxury Product: $name"
}
fun main() {
val p = product("Book")
println(p.description())
println(p.load())
val lp = LuxuryProduct("Gold")
println(lp.description())
println(lp.load())
}
2.检查类型
Kotlin中is
运算符可以用来检查某个对象的类型。
println(lp is product) // true
println(lp is LuxuryProduct) // true
println(p is LuxuryProduct) // false
3.类型转换
if(p is LuxuryProduct){
println((p as LuxuryProduct).special())
}
4.Any超类
在 Kotlin 中所有类都有一个共同的超类 Any
,Any 有三个方法:equals()
、 hashCode()
与 toString()
。因此,为所有 Kotlin 类都定义了这些方法。
5.object关键字
- 使用object关键字,可以定义一个只能产生一个实例的类-单例
- 使用object关键字有三种方式:对象声明、对象表达式、伴生对象
- 单例模式
object 可以用来声明一个单例对象。这种对象在整个程序中只有一个实例,并且可以包含属性和方法。
object Singleton {
val prop: String = "I'm a singleton property"
fun doSomething() {
println("Doing something in the singleton")
}
}
fun main() {
// 直接通过名称访问单例
println(Singleton.prop) // 输出 I'm a singleton property
Singleton.doSomething() // 输出 Doing something in the singleton
}
2.伴生对象(Companion Object)
object 还可以用于定义伴生对象。伴生对象是与类关联的一个单例对象,通常用于提供静态成员或工厂方法。
class MyClass {
companion object Factory {
fun createInstance(): MyClass {
return MyClass()
}
val someProperty: String = "This is a companion object property"
}
}
fun main() {
val instance = MyClass.createInstance()
println(MyClass.someProperty) // 输出 This is a companion object property
}
在这个例子中,Factory 是 MyClass 的伴生对象。你可以直接通过类名访问伴生对象中的方法和属性。
3.对象表达式
object 表达式还可以用来创建一个临时的对象实例,这个对象可以继承自某个类或实现某个接口。
open class BaseClass(val name: String) {
open fun sayHello() {
println("Hello, $name")
}
}
fun main() {
val obj = object : BaseClass("Kotlin") {
override fun sayHello() {
super.sayHello()
println("Nice to meet you!")
}
}
obj.sayHello()
// 输出:
// Hello, Kotlin
// Nice to meet you!
}
6.嵌套类
如果一个类只对另一个类有用,那么将其嵌入到该类中并使这两个类保持在一起是合乎逻辑的,可以使用嵌套类。
class Animal {
class Dog(var name:String){
fun show() = print("Dog is $name")
}
fun battle(){
}
}
fun main(){
val dog = Animal.Dog("Jack")
dog.show()
}
7.数据类
- 数据类是专门设计用来存储数据的类
- 数据类提供了
toString
的个性化实现 - ==符号默认情况下,比较对象就是他们的引用值,数据类提供了
equals
和hashCode
个性化实现。
data class Coordinate (var x :Int,var y:Int){
val isInBounds = x > 0 && y > 0
}
fun main() {
println(Coordinate(10,20))
println(Coordinate(10,20) == Coordinate(10,20)) // true
}
反编译:
@NotNull
public String toString() {
return "Coordinate(x=" + this.x + ", y=" + this.y + ')';
}
public int hashCode() {
int result = Integer.hashCode(this.x);
result = result * 31 + Integer.hashCode(this.y);
return result;
}
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
} else if (!(other instanceof Coordinate)) {
return false;
} else {
Coordinate var2 = (Coordinate)other;
if (this.x != var2.x) {
return false;
} else {
return this.y == var2.y;
}
}
}
8.copy函数
copy
函数是数据类(data class)的一个重要特性。它允许你创建一个现有对象的副本,并可以选择性地修改其中的一些属性。copy
函数自动生成,因此你无需手动编写它。
data class Person1(val name: String, var age: Int, val email: String)
fun main() {
val alice = Person1("Alice", 30, "[email protected]")
// 创建一个新对象,只更改年龄
val olderAlice = alice.copy(age = 31)
println(alice) // 输出: Person(name=Alice, age=30, [email protected])
println(olderAlice) // 输出: Person(name=Alice, age=31, [email protected])
}
9.解构声明
自定义类中实现 componentN() 函数来支持解构声明:
class PlayerScore(val experience:Int,val level:Int){
operator fun component1() = experience
operator fun component2() = level
}
fun main() {
val(experience,level) = PlayerScore(100,1)
println("experience: $experience")
println("level: $level")
}
对于数据类,Kotlin 会自动为每个属性生成 componentN() 函数,这使得可以直接解构数据类的实例:
data class Person1(val name: String, var age: Int, val email: String)
fun main() {
val alice = Person1("Alice", 30, "[email protected]")
// 创建一个新对象,只更改年龄
val olderAlice = alice.copy(age = 31)
println(alice) // 输出: Person(name=Alice, age=30, [email protected])
println(olderAlice) // 输出: Person(name=Alice, age=31, [email protected])
val (name, age, email) = alice
println("Name: $name, Age: $age, Email: $email")
}
10.运算符重载
如果要将内置运算符应用在自定类身上,必须重写运算符函数,告诉编译器该如何操作自定义类。
import kotlin.math.pow
import kotlin.math.sqrt
data class Coordinate2(var x: Int, var y: Int) {
operator fun plus(other: Coordinate2) = Coordinate2(x + other.x, y + other.y)
operator fun minus(other: Coordinate2) = Coordinate2(x - other.x, y - other.y)
fun distanceTo(other: Coordinate2): Double {
return sqrt((x - other.x).toDouble().pow(2) + (y - other.y).toDouble().pow(2))
}
override fun toString(): String {
return "Coordinate2(x=$x, y=$y)"
}
}
fun main() {
val coordinate2 = Coordinate2(10, 20)
val coordinate3 = Coordinate2(30, 40)
val resultPlus = coordinate2 + coordinate3
println("coordinate2 + coordinate3 = $resultPlus") // 输出: coordinate2 + coordinate3 = Coordinate2(x=40, y=60)
val resultMinus = coordinate2 - coordinate3
println("coordinate2 - coordinate3 = $resultMinus") // 输出: coordinate2 - coordinate3 = Coordinate2(x=-20, y=-20)
val distance = coordinate2.distanceTo(coordinate3)
println("Distance between coordinate2 and coordinate3 = $distance") // 输出: Distance between coordinate2 and coordinate3 = 28.284271247461902
}
11.枚举类
枚举类,用来定义常量集合的一种特殊类。
enum class Direction {
NORTH, SOUTH, EAST, WEST
}
enum class Color(val rgb: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF)
}
enum class Direction {
NORTH{
override fun toString(): String {
return "go to north"
}
}, SOUTH{
override fun toString(): String {
return "go to south"
}
}, EAST{
override fun toString(): String {
return "go to east"
}
}, WEST{
override fun toString(): String {
return "go to west"
}
}
}
fun main() {
println(Direction.EAST) // go to east
}
12.代数数据类型
可以用来表示一组子类型的闭集,枚举类就是一种简单的ADT
enum class LicenceStatus {
UNQUALIFIED,
LEARNING,
QUALIFIED
}
class Driver(var status : LicenceStatus){
fun checkLicence() : String {
return when(status){
LicenceStatus.QUALIFIED -> "You can drive"
LicenceStatus.LEARNING -> "You can learn to drive"
LicenceStatus.UNQUALIFIED -> "You can not drive"
}
}
}
fun main() {
val driver = Driver(LicenceStatus.UNQUALIFIED)
println(driver.checkLicence()) // You can not drive
}
13.密封类
密封类(Sealed Class)是 Kotlin 中的一种特殊类,它用来表示受限的类层次结构。这意味着密封类的所有直接子类都必须在同一个文件中定义,或者作为密封类的嵌套类来定义。这种设计有助于确保类型安全,并且可以让你更清晰地控制继承关系。
- 限制类层次:通过限制哪些类可以继承一个特定的基类,你可以更好地控制可能的数据类型。
- 模式匹配:当使用 when 表达式时,编译器能够确保你已经处理了所有可能的情况,避免遗漏任何一种情况。
sealed class Result {
data class Success(val data: String) : Result()
data class Error(val message: String) : Result()
object Loading : Result()
}
fun handleResult(result: Result) = when (result) {
is Result.Success -> println("Success: ${result.data}")
is Result.Error -> println("Error: ${result.message}")
Result.Loading -> println("Loading...")
}
// 调用示例
handleResult(Result.Success("Data loaded"))
handleResult(Result.Error("Failed to load data"))
handleResult(Result.Loading)
在这个例子中,handleResult 函数使用 when 表达式来处理不同类型的 Result。由于 Result 是一个密封类,编译器会检查 when 表达式是否覆盖了所有可能的子类。如果遗漏了任何一个子类,编译器将报错。
优点
- 类型安全:编译器可以确保你已经处理了所有可能的子类,从而减少了运行时错误的可能性。
- 简洁性:使用 when 表达式时,不需要写冗长的 else 分支来处理未知情况。
- 可维护性:当你需要添加新的子类时,只需要在一个地方进行修改,并且编译器会强制你在所有相关的 when 表达式中添加相应的处理逻辑。