深入探索Kotlin的面向对象编程世界(下)
2023-12-03 12:04:11
继承
继承是面向对象编程中最重要的特性之一。它允许你创建一个新类(子类),该类从另一个类(父类)继承属性和行为。这使得你可以轻松地创建新的类,而无需重复编写相同的代码。
class Person(val name: String, val age: Int)
class Student(name: String, age: Int, val major: String) : Person(name, age)
fun main() {
val student = Student("Alice", 20, "Computer Science")
println(student.name) // Alice
println(student.age) // 20
println(student.major) // Computer Science
}
在这个例子中,Student
类从 Person
类继承。这使得 Student
类具有 Person
类的所有属性和行为,还允许 Student
类定义自己的属性和行为。
属性
属性是对象的特征或状态。属性可以是只读的,也可以是可写的。
class Person(val name: String, var age: Int)
fun main() {
val person = Person("Alice", 20)
println(person.name) // Alice
person.age = 21
println(person.age) // 21
}
在这个例子中,Person
类具有两个属性:name
和 age
。name
属性是只读的,而 age
属性是可写的。
抽象类
抽象类是不能被实例化的类。抽象类可以包含抽象方法,抽象方法没有实现。子类必须实现抽象类中的所有抽象方法,才能被实例化。
abstract class Shape {
abstract fun area(): Double
}
class Rectangle(val width: Double, val height: Double) : Shape() {
override fun area(): Double {
return width * height
}
}
class Circle(val radius: Double) : Shape() {
override fun area(): Double {
return Math.PI * radius * radius
}
}
fun main() {
val rectangle = Rectangle(5.0, 10.0)
println(rectangle.area()) // 50.0
val circle = Circle(5.0)
println(circle.area()) // 78.53981633974483
}
在这个例子中,Shape
类是一个抽象类,它包含一个抽象方法 area()
。Rectangle
类和 Circle
类是 Shape
类的子类,它们都实现了 area()
方法。
接口
接口是一个定义了方法签名的类。接口不能被实例化,但它可以被其他类实现。实现接口的类必须实现接口中定义的所有方法。
interface Drawable {
fun draw()
}
class Rectangle(val width: Double, val height: Double) : Drawable {
override fun draw() {
println("Drawing a rectangle with width $width and height $height")
}
}
class Circle(val radius: Double) : Drawable {
override fun draw() {
println("Drawing a circle with radius $radius")
}
}
fun main() {
val rectangle = Rectangle(5.0, 10.0)
rectangle.draw() // Drawing a rectangle with width 5.0 and height 10.0
val circle = Circle(5.0)
circle.draw() // Drawing a circle with radius 5.0
}
在这个例子中,Drawable
接口定义了一个方法 draw()
。Rectangle
类和 Circle
类都实现了 Drawable
接口,并且都实现了 draw()
方法。
伴生对象
伴生对象是一个与类关联的对象。伴生对象可以包含与类相关的属性和方法。伴生对象可以使用类名来访问。
class Person(val name: String, val age: Int) {
companion object {
val DEFAULT_AGE = 18
}
fun getAge(): Int {
return if (age == 0) DEFAULT_AGE else age
}
}
fun main() {
val person = Person("Alice", 0)
println(person.getAge()) // 18
val defaultAge = Person.DEFAULT_AGE
println(defaultAge) // 18
}
在这个例子中,Person
类有一个伴生对象,它包含一个属性 DEFAULT_AGE
和一个方法 getAge()
。getAge()
方法使用 DEFAULT_AGE
属性作为默认值来返回对象的年龄。
密封类
密封类是一个受限的类,它只能被其嵌套类继承。密封类可以用来表示一组相关的类,并且可以防止创建不属于该组的类。
sealed class Shape {
class Rectangle(val width: Double, val height: Double) : Shape()
class Circle(val radius: Double) : Shape()
}
fun main() {
val shape: Shape = Circle(5.0)
when (shape) {
is Rectangle -> println("Rectangle with width ${shape.width} and height ${shape.height}")
is Circle -> println("Circle with radius ${shape.radius}")
}
}
在这个例子中,Shape
类是一个密封类,它有两个嵌套类:Rectangle
类和 Circle
类。main()
函数创建了一个 Shape
类型的变量 shape
,并将它设置为一个 Circle
对象。然后,when
语句用于根据 shape
的类型来执行不同的操作。
数据类
数据类是一种特殊的类,它提供了开箱即用的 toString()
、equals()
和 hashCode()
方法。数据类还支持解构,这使得可以轻松地将数据类对象分解为其各个属性。
data class Person(val name: String, val age: Int)
fun main() {
val person = Person("Alice", 20)
println(person) // Person(name=Alice, age=20)
val (name, age) = person
println("$name is $age years old") // Alice is 20 years old
}
在这个例子中,Person
类是一个数据类。main()
函数创建了一个 Person
对象 person
,并将其打印到控制台。然后,person
对象被解构为两个变量 name
和 age
,并将其打印到控制台。
封装和多态
封装是将数据的表示与操作分离。多态是指父类和子类可以具有相同的方法名,但是这些方法在不同的子类中具有不同的实现。
abstract class Shape {
abstract fun area(): Double
}
class Rectangle(val width: Double, val height: Double) : Shape() {
override fun area(): Double {
return width * height
}
}
class Circle(val radius: Double) : Shape() {
override fun area(): Double {
return Math.PI * radius * radius
}
}
fun main() {
val shapes: List<Shape> = listOf(
Rectangle(5.0, 10.0),
Circle(5.0)
)
for (shape in shapes) {
println(shape.area()) // 50.0, 78.53981633974483
}
}
在这个例子中,Shape
类是一个抽象类,它包含一个抽象方法 area()
。Rectangle
类和 Circle
类都是 Shape
类的子类,它们都实现了 area()
方法。main()
函数创建了一个 Shape
类型的列表 shapes
,并使用 for
循环来遍历该列表。在每个循环中,area()
方法都被调用来计算每个形状的面积。
委托
委托是一种在类中使用其他类的属性和方法的方式。委托类必须实现一个或多个接口,委托类中的属性和方法可以直接在委托类中使用。
interface Drawable {
fun draw()
}
class Rectangle(val width: Double, val height: