kotlin入门
Posted 临风而眠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kotlin入门相关的知识,希望对你有一定的参考价值。
Kotlin入门(2)
类与继承
文章目录
一.引入
下面围绕此情景展开:
基类为住处Dwelling
,子类为方形小木屋 (SquareCabin
)、圆形小屋 (RoundHut
) 和圆形塔楼 (RoundTower
)(即多楼层的 RoundHut
)
也就是将要实现以下的类:
Dwelling
:一个表示非特定住房的基类,可存储所有住房通用的信息。SquareCabin
:用木材建成的方形小木屋,建筑平面为方形。RoundHut
:用稻草搭成的圆形小屋,建筑平面为圆形,它是RoundTower
的父级。RoundTower
:用石头建成的多楼层圆形塔楼,建筑平面为圆形。
属性有:
方法有:
二.创建父类
先看代码
abstract class Dwelling(private var residents: Int) {
//实际人数,可能会变,用var
abstract val buildingMaterial: String //建筑材质,一般不会变,用val
abstract val capacity: Int //最大人容量,一般不会变,用val
fun hasRoom(): Boolean {
return residents < capacity
}
}
我们从C++的写法跳到这里肯定会对abstract是啥有疑问
1.why abstract
abstract,抽象的,顾名思义,抽象的没法和具体的东西一样,所以abstract类就相当于给一类东西抽象出一个概念
比如房屋,房屋有哪些属性呢,体积:高矮胖瘦;结构:卷我屋上三重茅或者固若金汤混凝土;价格:曹县一张床,浦东一套房…
房屋这个概念所包含的东西太多了,而从中抽出随便一种建筑,你的属性都可以从房屋这个概念里面抽取变成具体的子类
buildingMaterial和capacity属性作为抽象类的属性,也无法具体给值,所以也加上abstract 关键字
2.private
private标记的属性只能在此类中使用,(没有用private的属性和方法默认为public,这个和C++差不多)
放在情境中看,住的人数应该是隐私信息,也合理
3.构造函数
abstract class Dwelling(private var residents: Int)
和C++差别较大,构造函数就写在括号内
注:
抽象类无法实例化一个对象
比如下面这个代码就会报错
val a = Dwelling()
三.创建子类
还是先看代码:
fun main() {
val squareCabin = SquareCabin(6)
with(squareCabin) {
println("\\nSquare Cabin\\n============")
println("Capacity: ${capacity}")
println("Material: ${buildingMaterial}")
println("Has room? ${hasRoom()}")
}
val roundHut = RoundHut(3)
with(roundHut) {
println("\\nRound Hut\\n=========")
println("Material: ${buildingMaterial}")
println("Capacity: ${capacity}")
println("Has room? ${hasRoom()}")
}
}
abstract class Dwelling(private var residents: Int) {
abstract val buildingMaterial: String
abstract val capacity: Int
fun hasRoom(): Boolean {
return residents < capacity
}
}
class SquareCabin(residents: Int) : Dwelling(residents) {
override val buildingMaterial = "Wood"
override val capacity = 6
}
class RoundHut(residents: Int) : Dwelling(residents) {
override val buildingMaterial = "Straw"
override val capacity = 4
}
运行结果如下:
1.继承关系
需要在子类后面加冒号
class SquareCabin : Dwelling()
前面说到了Dwelling的构造函数,构造函数是自动调用的,而Dwelling的构造函数需要传参,所以括号里要传个Int型的数字
class SquareCabin : Dwelling(11)
但这样不方便后期修改程序,可以将父类的residents作为参数,这也同时构成了SquareCabin的构造函数
class SquareCabin(residents: Int) : Dwelling(residents)
传入参数给SquareCabin的时候,相当于赋值给了residents,于是先调用子类的构造函数,再调用父类的构造函数
2.override
前面是abstract,abstract关键字是不能实例化的,所以就要使其能够作为 可以实例化的子类 的属性
SquareCabin
是 Dwelling
的子类,因此它必须为 buildingMaterial
提供值。使用 override
关键字来表明此属性是在父类中定义的,并且在此类中将被替换掉
3.with
简化作用,如果没有with,前面相应的代码要改成
fun main() {
val squareCabin = SquareCabin(6)
println("\\nSquare Cabin\\n============")
println("Capacity: ${squareCabin.capacity}")
println("Material: ${squareCabin.buildingMaterial}")
println("Has room? ${squareCabin.hasRoom()}")
}
所以with语句的意思就是对with后面括号里面的对象执行{}内的操作,不需要输入”对象.属性“或者”对象.方法“
注
hasRoom()
函数不是在 SquareCabin
类中定义的,而是在 Dwelling
类中定义的。由于 SquareCabin
是 Dwelling
类的子类,hasRoom()
函数没有添加abstract关键字,可以直接继承。
现在,可以在 SquareCabin
的所有实例上调用 hasRoom()
函数,如上面代码段所示
4.继续继承
引入中讲到
RoundHut
是 RoundTower
的父级。
可是我们用下面这段代码会报错:
class RoundTower(residents: Int) : RoundHut(residents) {
override val buildingMaterial = "Stone"
override val capacity = 4
}
报错如下:
This type is final, so it cannot be inherited from
在 Kotlin 中,类是最终层级,无法被子类化。只能从 abstract
类或标记有 open
关键字的类继承。因此,使用 open
关键字标记 RoundHut
类,使其能够被继承
完整代码如下(给RoundTower添加了楼层属性,给了默认值2)
fun main() {
val squareCabin = SquareCabin(6)
val roundHut = RoundHut(3)
val roundTower = RoundTower(4)
with(squareCabin) {
println("\\nSquare Cabin\\n============")
println("Capacity: ${capacity}")
println("Material: ${buildingMaterial}")
println("Has room? ${hasRoom()}")
}
with(roundHut) {
println("\\nRound Hut\\n=========")
println("Material: ${buildingMaterial}")
println("Capacity: ${capacity}")
println("Has room? ${hasRoom()}")
}
with(roundTower) {
println("\\nRound Tower\\n==========")
println("Material: ${buildingMaterial}")
println("Capacity: ${capacity}")
println("Has room? ${hasRoom()}")
}
}
abstract class Dwelling(private var residents: Int) {
abstract val buildingMaterial: String
abstract val capacity: Int
fun hasRoom(): Boolean {
return residents < capacity
}
}
class SquareCabin(residents: Int) : Dwelling(residents) {
override val buildingMaterial = "Wood"
override val capacity = 6
}
open class RoundHut(residents: Int) : Dwelling(residents) {
override val buildingMaterial = "Straw"
override val capacity = 4
}
class RoundTower(
residents: Int,
val floors: Int = 2) : RoundHut(residents) {
override val buildingMaterial = "Stone"
override val capacity = 4 * floors
}
不给floors默认值也可以这样,也就是多传一个参数
val roundTower = RoundTower(4,1)
class RoundTower(
residents: Int,
val floors: Int) : RoundHut(residents) {
override val buildingMaterial = "Stone"
override val capacity = 4 * floors
}
增设情景
下面还将增计算建筑面积
,允许新客获得房间
,为圆形住房准备合适的地毯
,先看完整代码
/**
* 各种房屋类
* 主要包含:
* 方法和属性的继承
* abstract class, overriding, and private 与 public 变量.
*/
import kotlin.math.PI
import kotlin.math.sqrt
fun main() {
val squareCabin = SquareCabin(6, 50.0)
val roundHut = RoundHut(3, 10.0)
val roundTower = RoundTower(4, 15.5)
with(squareCabin) {
println("\\nSquare Cabin\\n============")
println("Capacity: ${capacity}")
println("Material: ${buildingMaterial}")
println("Floor area: ${floorArea()}")
}
with(roundHut) {
println("\\nRound Hut\\n=========")
println("Material: ${buildingMaterial}")
println("Capacity: ${capacity}")
println("Floor area: ${floorArea()}")
println("Has room? ${hasRoom()}")
getRoom()
println("Has room? ${hasRoom()}")
getRoom()
println("Carpet size: ${calculateMaxCarpetSize()}")
}
with(roundTower) {
println("\\nRound Tower\\n==========")
println("Material: ${buildingMaterial}")
println("Capacity: ${capacity}")
println("Floor area: ${floorArea()}")
println("Carpet size: ${calculateMaxCarpetSize()}")
}
}
/**
* 定义了所有住处都有的属性
* 每种房屋都有楼层面积,
* 但楼层面积的计算方法不同(受形状影响),要由子类具体复写实现.
* 判断客房是否满了还有允许新客获得房间在Dwelling类里面就实现了,这样它就能够用于所有子类及其子级
* 因为每个子类的这两个方法都是一样的.
*
* @param residents Current number of residents
*/
abstract class Dwelling(private var residents: Int) {
abstract val buildingMaterial: String
abstract val capacity: Int
/**
* 计算楼层面积.
* 由各子类具体复写实现.
*
* @return floor area
*/
abstract fun floorArea(): Double
/**
* 判断是否能容纳新客.
*
* @return true if room available, false otherwise
*/
fun hasRoom(): Boolean {
return residents < capacity
}
/**
* 比较容量和实际人数
* 如果容量
* 通过增加数字体现人数增加
* 输出结果
*/
fun getRoom() {
if (capacity > residents) {
residents++
println("You got a room!")
} else {
println("Sorry, at capacity and no rooms left.")
}
}
}
/**
* 方形小屋
*
* @param residents Current number of residents
* @param length Length
*/
class SquareCabin(residents: Int, val length: Double) : Dwelling(residents) {
override val buildingMaterial = "Wood"
override val capacity = 6
/**
* 计算方形小屋的楼层面积
*
* @return floor area
*/
override fun floorArea(): Double {
return length * length
}
}
/**
* 圆形小屋
*
* @param residents Current number of residents
* @param radius Radius
*/
open class RoundHut(
val residents: Int, val radius: Double) : Dwelling(residents) {
//radius 半径
override val buildingMaterial = "Straw"
override val capacity = 4
/**
* 计算圆形小屋的楼层面积
*
* @return floor area
*/
override fun floorArea(): Double {
return PI * radius * radius
}
/**
* 计算最大的适用于圆形小屋的方形地毯的面积
*
* @return length of carpet
*/
fun calculateMaxCarpetSize(): Double {
val diameter = 2 * radius //diameter直径
return sqrt(diameter * diameter / 2)
}
}
/**
* 有多层楼的圆形塔楼
*
* @param residents Current number of residents
* @param radius Radius
* @param floors Number of stories
*/
class RoundTower(
residents: Int,
radius: Double,
val floors: Int = 2) : RoundHut(residents, radius) {
override val buildingMaterial = "Stone"
//容量由楼层决定.
override val capacity = floors * 4
/**
* 计算圆形塔楼面积
*
* @return floor area
*/
override fun floorArea(): Double {
return super.floorArea() * floors
}
}
对代码的注释进行补充:
Dwelling
具有构造函数参数residents
,因此其所有子类都具有该参数。由于这是Dwelling
构造函数中的第一个参数,所以最好也将其作为所有子类构造函数中的第一个参数,并在所有类定义中以相同的顺序排列参数。因此,各个子类插入新参数的时候最好都在residents
后面插入- 导入语句要放在文件顶部,main函数前面
RoundTower
类定时要具有与其父级RoundHut
相同的radius
参数(从父类扩展,您必须传入父类所需的参数)- 使用如下代码
override fun floorArea(): Double {
return super.floorArea() * floors
}
是使用了 super
关键字,调用父级中定义的函数,好处是可以避免类似的代码
override fun floorArea(): Double {
return PI * radius * radius * floors
}
四.总结
(官方文档上的总结)
- 创建一个类层次结构,这是一种包含类的树形结构,其中子级会继承父类的函数。子类继承的有属性和函数。
- 创建一个
abstract
类,在这种类中,部分函数会留给其子类来实现。因此,abstract
类无法被实例化。 - 创建
abstract
类的子类。 - 使用
override
关键字,在子类中替换属性和函数。 - 使用
super
关键字,引用父类中的函数和属性。 - 将一个类标记为
open
,使其能够被子类化。 - 将一个属性标记为
private
,使其只能在相应类中使用。 - 使用
with
构造函数,在同一对象实例上进行多次调用。 - 从
kotlin.math
库导入函数
突然想到红警里面各种建筑了(那种可以把美国大兵塞进去的),有的可以放很多美国大兵,有的抗打,有茅草屋,有碉堡…把那个情景引入进来挺好的哈哈哈😺
以上是关于kotlin入门的主要内容,如果未能解决你的问题,请参考以下文章