Kotlin继承
继续我们的Kotlin系列教程,今天,我们将探讨Kotlin类中的继承。
让我们开始创建一个新的IntelliJ IDEA Kotlin项目。
Kotlin继承
继承是创建类层次结构的概念,其中我们根据需要在基类的子类中覆盖基类的属性和功能。
Kotlin中的所有类都有一个共同的超类:Any。
继承允许代码可重用。
通常,超类称为基类或者父类,子类为派生/子类。
由于存在著名的钻石问题,Kotlin不允许一个类从多个类继承。
Kotlin继承示例
让我们将上述继承概念放在下面的示例代码中。
我们创建了一个基类,如下所示:
open class Employee(eName: String) {
init {
println("He/She is an employee")
}
open var name = eName
var age: Int = 24
open fun printDetails() {
println("Employee Name is $name. No specific details are available in this function.")
}
}
默认情况下,Kotlin中的所有类都是"最终"类。
因此,要允许继承一个类,我们需要在该类之前附加open修饰符,以使其成为非最终类。
另外,要允许覆盖属性和函数,我们也需要在其上设置open修饰符。
一旦创建了类的实例,就会执行init()函数。
以下代码包含派生类,该派生类扩展了上述类。
open class Developer(dName: String, income: Int) : Employee(dName) {
init {
println("He/She is an a Developer")
}
override var name = dName
open var salary = income
override fun printDetails() {
println("Dev name is $name and salary is $salary")
}
}
要从类继承,我们需要在
:之后设置基类签名。如果派生类(开发人员)具有主构造函数,则需要在此使用派生类的参数初始化基类(员工)构造函数。
如果派生类没有主要构造函数,则需要使用关键字" super"在次要构造函数中调用基类构造函数。
要覆盖具有完全相同类型的基类中的属性或者函数,您需要在其后附加
override以防止编译错误。如果在基类中未打开功能和/或者未在基类中设置" override"修饰符,则不能在具有相同签名的派生类中声明功能/属性。
让我们在Kotlin类的主要函数中运行以上代码,以了解程序的流程。
fun main(args: Array<String>) {
var employee = Employee("Anupam")
employee.printDetails()
println()
var developer = Developer("Hyman", 10000)
developer.printDetails()
println(developer.age) //gets the age property from the superclass
}
输出应如下所示:
创建开发人员类的实例时,它将首先调用超类的
init块,然后调用其自身的块。子类可以访问其超类的所有非私有属性和函数。
可以将超类实例设置为子类对象。
这样做,超类只能访问子类中被覆盖的属性和函数。
以下代码展示了将超类实例设置为子类的方法。
employee = developer employee.printDetails() //Dev name is Hyman and salary is 10000 println(employee.name) //Prints Hyman
从上面的代码中可以明显看出,超类将打印重写的属性和函数。
现在,让我们创建"开发人员"类的子类。
class AndroidDeveloper(name: String, income: Int) : Developer(name, income) {
override var name = "aName property value is $name".also(::println)
override var salary: Int = 0
get() = field
set(value) {
if (value >= 100000) {
field = min(50000, value)
} else field = value
}
init {
println("He/She is an Android Developer. If Salary >= 100000. It's halved.")
salary = income
}
fun works() {
println("Builds Apps")
}
override fun printDetails() {
super.printDetails()
println("He's an Android Developer")
}
}
class JuniorDeveloper : Developer {
var aName = "Name is $name".also(::println)
init {
println("He/She is a Junior Developer.")
}
var mySkill: String?
override var salary: Int = 0
get() = field
set(value) {
if (value > 50000) {
field = min(10000, value)
} else field = value
}
constructor(name: String, income: Int, skill: String) : super(name, income) {
mySkill = skill
salary = income
}
override fun printDetails() {
println("Junior dev name is $name and salary is $salary, Skill is $mySkill")
}
}
" JuniorDeveloper"类没有主要的构造函数,因此我们使用" super"在辅助构造函数中调用超类。
在上述两个子类中,我们都在覆盖的属性"工资"中设置了自定义getter和setter。
在定义本身中首次分配属性值时,不会调用setter属性。
让我们再次在main函数中运行类实例。
val androidDeveloper = AndroidDeveloper("Rose", 100000)
androidDeveloper.printDetails()
androidDeveloper.salary = 100000
println("Updated Salary : ${androidDeveloper.salary}")
println("\nJunior Developer class......\n")
val juniorDeveloper = JuniorDeveloper("Brock", 60000, "Kotlin")
juniorDeveloper.printDetails()
juniorDeveloper.salary = 60000
println("Junior Dev new salary is ${juniorDeveloper.salary}")
println("Assigning juniordeveloper to super superclass\n")
employee = Employee("Anupam")
employee = juniorDeveloper
print(employee.salary)
打印以下输出。
因此,对于任何一个实例创建,都将首先调用超类的所有init块。
在JuniorDeveloper类中,我们必须在辅助构造函数中手动设置属性。
因此,对于" juniordeveloper"实例,属性设置器将立即被调用。
在代码的最后一部分,我们将employee实例设置为juniordeveloper实例以获取覆盖的属性。
下一个示例在类层次结构中一起使用接口和类。
open class Manager {
init {
println("He/She is a manager.")
}
open lateinit var mName: String
open var salary: Int? = null
constructor(name: String) {
mName = name
}
constructor(income: Int) {
salary = income
}
open fun printDetails() {
println("Name is $mName. Salary is $salary")
}
}
interface X {
fun printDetails() {
print("He has an X-Factor")
}
}
在课堂上,我们创建了两个辅助构造函数。
接口和类具有相同的功能签名。
让我们看看子类如何处理它。
class ProjectManager : Manager {
var numberOfProjects: Int?
var pName: String?
init {
println("He/She is a Project Manager.")
}
constructor(number: Int) : this("Ben", 10)
constructor(name: String, number: Int) : super(name) {
numberOfProjects = number
pName = "Congrats ${super.mName}"
}
override fun printDetails() {
super.printDetails()
println("$pName He's handled $numberOfProjects projects so far")
}
}
class BackendManager : Manager, X {
init {
println("He/She is a Backend Manager.")
}
var isBackendReady: Boolean?
val backendLanguage: String?
override var mName = "NA"
constructor(name: String, language: String) : super(name) {
println("Constructor 1 gets called.")
isBackendReady = false
backendLanguage = language
mName = name
}
constructor(isReady: Boolean, name: String) : this("Anupam", "PHP") {
println("Constructor 2 gets called.")
isBackendReady = isReady
}
override fun printDetails() {
super<Manager>.printDetails()
println("The backend he's working on, is it ready? $isBackendReady.")
super<X>.printDetails()
}
}
在class(ProjectManager)中,第一个构造函数使用this委托给第二个构造函数。
因此,第二个构造函数将在第一个构造函数之前执行。
super.mName用于从超类访问属性。
由于它是此类中的"可选",我们需要使用"?。
"运算符安全地将其解包。
由于函数签名在超类和接口中相同,因此要进行正确的调用,我们需要执行" super <Type> .printDetails()"。
创建上述类的实例时的输出如下。
var manager = Manager("Thomas")
manager.printDetails()
println()
manager = ProjectManager(number = 10, name = "Ben")
manager.printDetails()
println()
val backendManager = BackendManager(true, "Smith")
backendManager.printDetails()
在BackendManager类中,调用构造函数2,该构造函数首先执行构造函数1。

