我是科特林的新手。我正在 kotlin 中浏览嵌套类和内部类概念。下面是一个嵌套类的例子。
fun main(args: Array<String>) {
val demo = Outer.Nested().foo() // calling nested class method
print(demo)
}
class Outer {
class Nested {
fun foo() = "Hello world"
}
}
Run Code Online (Sandbox Code Playgroud)
这给出了输出
Hello world
Run Code Online (Sandbox Code Playgroud)
这是内部类的例子。
fun main(args: Array<String>) {
val demo = Outer().Nested().foo() // calling inner class method
print(demo)
}
class Outer {
private val welcomeMessage: String = "Hello world"
inner class Nested {
fun foo() = welcomeMessage
}
}
Run Code Online (Sandbox Code Playgroud)
这给出了输出
Hello world
Run Code Online (Sandbox Code Playgroud)
我的问题是嵌套类何时可以执行与内部类相同的操作。内部类的目的是什么?为什么我们需要实时内部类?
Kotlin 官方文档非常不言自明:
标记为内部的嵌套类可以访问其外部类的成员。内部类携带对外部类的对象的引用:
也许你不明白这意味着什么。
具体来说,在您的代码示例中,您只能访问from code in when标记为 中welcomeMessage定义的。尝试删除,您的代码将无法编译。OuterNestedNestedinnerinner
嵌套类本身是一个相当简单的概念,即一个概念在逻辑上依赖于另一个更广泛的概念。每当您发现自己描述了一个如此广泛的概念的构建块时,您就想声明一个新的嵌套类,而您不希望自己凭空出现在您的业务逻辑中。因此,此类类的实例可以通过它嵌套在其中的类的定义来访问。
以下面的结构为例:
class Parrot(val name: String): Animal {
//vals and vars useful for a parrot
class HealthyConditions {
val featherColour: String // Does not really apply to Dogs, Cats, Fish, etc.
val cageSize: Size // Does not really apply to Dogs, Cats, Fish, etc.
val weightInGrammes: Int
val dailySleepInHours: Int
fun isUnderweight(currentWeightInGrammes: Int): Boolean {
return currentWeightInGrammes < weightInGrammes
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,健康生活条件的概念对于Animal该系统可能描述的任何系统来说都是常见且重要的,但从一个物种到另一个物种,需要考虑多个完全不同的因素。尝试HealthyConditions<Animal>一次为所有这些类准备一个公共类可能会导致代码不可读且难以维护,充满了ifs 和elses。因此,开发人员单独为每个类定义简洁、整洁的嵌套类可能更有意义Animal。后来,这些将通过访问Parrot.HealthyConditions(),Cat.HealthyConditions()等来代替HealthyConditions.getForSpecies(animal)。
内部类是建立在嵌套类思想之上的 Kotlin 概念。虽然一些细节对于给定的概念非常具体,因此被描述为嵌套类,但如果这些细节根据更广泛的概念的实例而进一步变化怎么办?然后使用类定义访问它可能不是正常操作所需的全部。因此,内部类是通过调用它们所属的类的实例来访问的。
让我们回到我们Parrot应该做的事情吗?
class Parrot(val name: String, var age: Int): Animal {
//vals and vars useful for a parrot
inner class HealthyConditions {
val featherColour: String // Does not really apply to Dogs, Cats, Fish, etc.
val cageSize: Size // Does not really apply to Dogs, Cats, Fish, etc.
val weightInGrammesByAge: Map<Int, Int>
val dailySleepInHoursByAge: Int<Int, Int>
/** variable 'age' from the Parrot class can be accessed only because the HealthyConditions class is marked inner! */
fun isUnderweight(currentWeightInGrammes: Int): Boolean {
return currentWeightInGrammes[age] < weightInGrammes
}
}
}
Run Code Online (Sandbox Code Playgroud)
Parrot在所述鹦鹉的一生中,健康的体重应该有多少变化。重达数百克的幼龟没问题,但低于 2 公斤的成年个体可能需要注意。因此,Parrotx 克时a是否体重不足的问题不能轻易回答,但是如果我们问鹦鹉鲍勃是否应该增加一些体重,我们可以使用我们对鲍勃的了解来确定答案。为了做到这一点,HealthyConditions该类将通过Parrot("Bob", 5).HealthyConditions().
现在,最重要的是,您可能仍然想知道访问父类属性对于内部类是否真的有用。毕竟,您可以简单地age在调用isUnderweight()函数的任何地方提供值,对吗?当然,这是真的,但是在讨论嵌套类时,我们认为每个类都Animal应该有自己的HealthyConditions实现。对于一个Dog等级,狗的品种在确定其正确体重方面与其年龄同样重要。对于其他物种,性别也很重要。这意味着,如果内部类不能直接访问其父类的属性,则Healthcheck接口的函数checkIfUnderweight()将不得不接受大量不同的、可能为空的变量,以便适用于系统中的所有不同种类的动物。
我花了很多时间在没有很多代码示例的情况下讨论这个概念,但据我所知,您并没有为实现而烦恼,而是有理由甚至首先实现代码。另外,如果我想出的“动物课程”示例可能显得笨拙,请原谅我 - 事实是它是我想出的第一个。;)
无论如何,我希望这篇简短的阅读可以帮助您更好地理解这个概念及其用例。安全编码,让错误远离您!