-
繼承與重載的關(guān)鍵字open
類默認(rèn)都是封閉的,要想某個(gè)類開(kāi)放繼承,必須使用open關(guān)鍵字修飾它
在main函數(shù)中調(diào)用
//繼承
val carProduct : Product = CarProduct()
println(carProduct.description())
println(carProduct.load())
//繼承
open class Product(val name : String){
fun description () = "Product === $name"
open fun load () = "Loading..."
}
//繼承父類,父類必須用open關(guān)鍵字,否則默認(rèn)類是final
class CarProduct:Product("aodi"){
//這里的override是關(guān)鍵字,重寫(xiě)某父類方法需要加override,并且父類方法必須聲明為open
override fun load () ="aodi Loading..."
fun carMethod() = "car special Method"
}
-
類型轉(zhuǎn)換
is as 關(guān)鍵字
kotlin中的Any超類,類似于java中的object
//類型轉(zhuǎn)換
println(carProduct is Product)
println(carProduct is CarProduct)
if(carProduct is CarProduct){
println((carProduct as CarProduct).carMethod())
}
-
對(duì)象聲明
使用object關(guān)鍵字,可以定義一個(gè)只能產(chǎn)生一個(gè)實(shí)例的類--單例
使用object關(guān)鍵字有三種方式
1.對(duì)象聲明
//在kotlin中,聲明一個(gè)類為單例很方便,直接使用object
object ApplicationConfig{
init {
println("applicationConfig init...")
}
fun doSomething(){
println("doSomething")
}
}
在main函數(shù)中調(diào)用
//在kotlin中,聲明一個(gè)類為單例很方便,直接使用object
ApplicationConfig.doSomething()//這里并不是說(shuō)是靜態(tài)的,而是聲明了是單例類,這里就可以直接使用類名作為對(duì)象名
//指向的都是同一個(gè)對(duì)象,因?yàn)樗菃卫? println(ApplicationConfig)
println(ApplicationConfig)
println(ApplicationConfig)
2.對(duì)象表達(dá)式
open class Player8 {
open fun load() = "loading nothing"
}
在main函數(shù)中調(diào)用
//對(duì)象表達(dá)式作為子類
//類似于java中的new 一個(gè)OnclickListener,這個(gè)匿名類依然遵循object關(guān)鍵字的原則,一旦實(shí)例化,只能有唯一一個(gè)實(shí)例存在
val p = object : Player8(){
override fun load() = "匿名類的loading方法"
}
println(p.load())
3.伴生對(duì)象
//伴生對(duì)象
open class SinggleTest{
//只有初始化SinggleTest類或者調(diào)用load函數(shù)時(shí),伴生對(duì)象的內(nèi)容才會(huì)載入
//而且無(wú)論實(shí)例化多少次,這個(gè)伴生對(duì)象始終只有一個(gè)實(shí)例存在。有點(diǎn)類似java的static
//一個(gè)類里只能有一個(gè)伴生對(duì)象
companion object{
private const val PATH = "xxxxxxx"
fun load() = println("伴生對(duì)象的方法執(zhí)行")
}
}
在main函數(shù)中調(diào)用
//伴生對(duì)象
SinggleTest.load()
- 嵌套類
//嵌套類(內(nèi)部類)
//如果一個(gè)類只對(duì)另一個(gè)類有用,那么將其嵌入到該類中并使兩個(gè)類保持在一起就很合邏輯,可以使用嵌套類
class Player1{
class Equipment(var name:String){
fun show() = println("equipment:$name")
}
fun battle() = println("ak47...")
}
在main函數(shù)中調(diào)用
//嵌套類(內(nèi)部類)
Player1.Equipment("天空套").show()
-
數(shù)據(jù)類
專門用來(lái)存儲(chǔ)數(shù)據(jù)的類
看源碼可以看到,默認(rèn)實(shí)現(xiàn)了toString方法,打印的時(shí)屬性值
==符合默認(rèn)情況下,在any超類里面比較的是它們的引用值,數(shù)據(jù)類提供了equals和hashcode的個(gè)性化實(shí)現(xiàn),比較的是內(nèi)容
/**
* 使用數(shù)據(jù)類的條件
* 對(duì)于那些經(jīng)常需要比較,復(fù)制或打印自身內(nèi)容的類,數(shù)據(jù)類很適用。然而,一個(gè)類要成為數(shù)據(jù)類,也要符合一定條件,總結(jié)下來(lái),主要有三個(gè)方面
* 1.數(shù)據(jù)類必須有至少帶一個(gè)參數(shù)的主構(gòu)造函數(shù)
* 2.數(shù)據(jù)類主構(gòu)造函數(shù)的參數(shù)必須是var 或者 val
* 3.數(shù)據(jù)類不能使用abstract,open,sealed和inner修飾符
*/
//數(shù)據(jù)類,用data關(guān)鍵字修飾
data class Coordinate(val x : Int,val y : Int){
}
在main函數(shù)中調(diào)用
//這里打印的是Coordinate(x=1, y=2)。如果不用data修飾,打印的是Coordinate@60e53b93
println(Coordinate(1,2))
//這里結(jié)果是true,如果類名不用data修飾,則是false
println(Coordinate(1,2) == Coordinate(1,2))
- copy函數(shù)
//data數(shù)據(jù)類的copy函數(shù)demo
data class StudentOrigin(
val name: String,
var age : Int,
var isNormal : Boolean
){
var score = 0
//次構(gòu)造函數(shù),有主就有次,我們可以定義多個(gè)次構(gòu)造函數(shù)來(lái)配置不同的參數(shù)組合
constructor(_name: String) : this (_name,age = 10,isNormal = false){
//copy函數(shù)不會(huì)調(diào)用這,copy出去的值還是0
score = 10
}
//初始化塊,與java的static不一樣,這里的初始化塊是構(gòu)造函數(shù)執(zhí)行的時(shí)候,就會(huì)執(zhí)行初始化快
init {
//先決函數(shù),如果boolean值是false,執(zhí)行l(wèi)ambda拋出異常
require(age > 0) {
"age must be positive"
}
require(name.isNotBlank()){
"student must have a name"
}
}
override fun toString(): String {
return "StudentOrigin(name='$name', age=$age, isNormal=$isNormal, score=$score)"
}
}
在main函數(shù)中調(diào)用
//copy函數(shù),它可以將數(shù)據(jù)類的其他屬性都copy過(guò)來(lái)。但是這里有一個(gè)坑,次構(gòu)造函數(shù)里面修改過(guò)的值不能copy,需要重新賦值
val s = StudentOrigin("Jack")
val copy = s.copy("Rose")
println(s)
println(copy)
- 解構(gòu)聲明
//解構(gòu)語(yǔ)法的demo類
class Demo(val x:Int , val y : Int){
//這里的component1等名字都是固定寫(xiě)法,不能修改
operator fun component1() = x
operator fun component2() = y
}
//數(shù)據(jù)類,用data關(guān)鍵字修飾
data class Coordinate(val x : Int,val y : Int){
}
在main函數(shù)中調(diào)用
//數(shù)據(jù)類默認(rèn)支持解構(gòu)語(yǔ)法,如果不是數(shù)據(jù)類,則需要我們手動(dòng)在類里面重寫(xiě)方法,就如果解構(gòu)語(yǔ)法demo類一樣。
val (x,y) = Coordinate(1,2)
println("$x,$y")
//解構(gòu)語(yǔ)法的demo類
val (a,b) = Demo(3,4)
println("$a,$b")
-
運(yùn)算符重載
使用operator關(guān)鍵字
/**
* 運(yùn)算符重載,常見(jiàn)的操作符
*
*
* 操作符 函數(shù)名 作用
* + plus 把一個(gè)對(duì)象添加到另一個(gè)對(duì)象里
* += plusAssign 把一個(gè)對(duì)象添加到另一個(gè)對(duì)象里,然后將結(jié)果賦值給第一個(gè)對(duì)象
* == equals 如果兩個(gè)對(duì)象相等,則返回true,否則返回false
* > compareTo 如果左邊的對(duì)象大于右邊的對(duì)象,就返回true,否則返回false
* [] get 返回集合中指定位置的元素
* .. rangeTo 創(chuàng)建一個(gè)range對(duì)象
* in contains 如果對(duì)象包含在集合里,則返回true
*
*/
data class Coordinate2(val x: Int,val y: Int){
//運(yùn)算符重載,使用operator關(guān)鍵字
operator fun plus(other:Coordinate2) = Coordinate2(x+other.x,y+other.y)
}
在main函數(shù)中調(diào)用
//運(yùn)算符重載
val coordinate2 = Coordinate2(10,50)
val coordinate3 = Coordinate2(20,100)
//如果下面的運(yùn)算符不重寫(xiě),這里使用+號(hào)就會(huì)報(bào)錯(cuò)
println(coordinate2+coordinate3)
-
枚舉類
枚舉類也可以定義函數(shù)
data class Coordinate2(val x: Int,val y: Int){
//運(yùn)算符重載,使用operator關(guān)鍵字
operator fun plus(other:Coordinate2) = Coordinate2(x+other.x,y+other.y)
}
//枚舉類,也可以定義函數(shù)
enum class Direction(val coordinate:Coordinate2){
EAST(Coordinate2(1,2)),
WEST(Coordinate2(3,4)),
NORTH(Coordinate2(5,6)),
SOUTH(Coordinate2(7,8));
fun updateCoordinate(other: Coordinate2) = Coordinate2(
other.x + coordinate.x,
other.y + coordinate.y
)
}
在main函數(shù)中調(diào)用
//枚舉類,用來(lái)定義常量集合的一種特殊類
println(Direction.EAST) //輸出的就是枚舉的字符串值
println(Direction.WEST.updateCoordinate(Coordinate2(10,20)))
-
密封類
密封類(sealed),從枚舉類思考更復(fù)雜的需求,比如我需要控制其中一個(gè)對(duì)象具有某種屬性,這時(shí)候使用密封類,但不要混淆,密封類不是枚舉
密封類可以用來(lái)定義一個(gè)類似于枚舉類的類型,但是可以更靈活的控制某個(gè)子類型
密封類可以有若干個(gè)子類,要繼承密封類,這些子類必須和它定義在同一個(gè)文件中
//密封類demo
class Driver(var status: LicenseStatus){
fun checkLicense () : String {
return when(status){
is LicenseStatus.Unqualified -> "沒(méi)資格"
is LicenseStatus.Learning -> "正在學(xué)"
is LicenseStatus.Qualified -> "有資格,駕駛證編號(hào): " + (this.status as LicenseStatus.Qualified).licenseId
}
}
}
//密封類
sealed class LicenseStatus{
object Unqualified : LicenseStatus() //這里沒(méi)有屬性,所以把它定義為單例
object Learning : LicenseStatus() //這里沒(méi)有屬性,所以把它定義為單例
class Qualified (var licenseId:String) : LicenseStatus() //這里有一個(gè)id的屬性,所以不定義為單例
}
在main函數(shù)中調(diào)用
println(Driver(LicenseStatus.Qualified("2820202")).checkLicense())
println(Driver(LicenseStatus.Learning).checkLicense())