1,類和接口
<1>類的相關概念
類的簡介
- 類是一個抽象的概念
- 類是具體某些特性的事物的概括
- 不特定指代任何一個具體的事物
- 例如:人,車,書 ;數(shù)字,字符串,字符也都是類
- 寫法 class<類名>{成員}
對象的簡介
- 對象是一個具體的概念,與類相對
- 指代某一種類的具體個體
類和對象的關系
- 一個類通常可以有很多個具體的對象
- 一個對象的本質只能從屬于一個類
- 對象經常被稱為類的對象或類的實例
<2>類的定義
class simpleClass1 {}
//一般的構造器寫法兒
class simpleClass2 {
var string: String
constructor(string: String) {
this.string = string
}
}
//主構造器
class simpleClass3(var string: String) {}
//主構造器和副構造器同時存在
class simpleClass4(var string: String) {
var arg: Int = 0
constructor(string: String, arg: Int) : this(string) {
this.arg = arg
}
}
//多個副構造器
class simpleClass5 {
var name: String = ""
var age: Int = 0
constructor(name: String) {
this.name = name
}
constructor(age: Int) {
this.age = age
}
}
Kotlin中有主構造器和副構造器的概念,主構造器會提取到類名的后面進行聲明,這樣每次構建該類時這必須通過主構造器,也可以在類中定義其他副構造器,但是所定義的副副構造器必須也有主構造器的聲明
<3>類的實例化
val testClass = simpleClass3("wjf")
println(testClass.string)
val testClass2 = simpleClass5(1)
println("${testClass2.age},${testClass2.name}")
<4>接口
接口的定義和實現(xiàn)
interface simpleInterface1 {
fun simpleMethod(age: Int): Int
}
class simpleImi : simpleInterface1 {
override fun simpleMethod(age: Int): Int {
return 1
}
}
與Java中不同的是Kotlin中override是一個關鍵字,當類實現(xiàn)接口時必須帶有該關鍵字
<5>抽象類
抽象類的定義
abstract class simpleABSClass {
abstract fun absfun()
open fun canBeOverride() {}
fun cannotBeOverride() {}
}
open class simpleAbsIme(name: String, age: Int) : simpleABSClass() {
override fun absfun() {
}
final override fun canBeOverride() {
super.canBeOverride()
println()
}
}
class childSimpleAbsIme(name: String, age: Int) : simpleAbsIme(name, age) {
//父類中的方法加了final 所以該子類不能被復寫
// override fun canBeOverride() {
// super.canBeOverride()
// println()
// }
}
這里有幾點需要注意
- 除了接口和抽象類外定義的類,默認是final類型的不能被繼承,如果想繼承該類必須在類上加"open"字段
- 除了接口和抽象類的類必須實現(xiàn)的方法外,默認定義的方法也是final類型的,如果子類想要復寫該方法,則必須在該方法前面加"open"字段
- 如果實現(xiàn)了接口或抽象的方法,不想再被子類復寫那么可以在該方法前面加"final"字段
<6>類的屬性和類的屬性引用
class Person(name: String, age: Int) {
//類的屬性,kotlin中自動生成getter和setter
var name: String = name
// get() {
// return field
// }
// set(value) {
// field=value
// }
var age: Int = age
// get() {
// return age
// }
// set(value) {
// field=value
// }
}
fun main(args: Array<String>) {
val aPerson = Person("WJF", 25)
//由于該引用沒有具體的實現(xiàn)類所以調用set的時候需要傳入具體的receiver
//類的屬性引用
val testNoClass = Person::name
testNoClass.set(aPerson, "WWJJFF")
//有具體實現(xiàn)類的屬性引用
val testHadClass = aPerson::name
testHadClass.set("WJF")
}
2,擴展方法和擴展屬性
- 一個類中沒有的方法可以通過擴展增加該方法
- 定義形式為:fun receiver.<方法名>(參數(shù)列表):<返回值類型>
- 調用:receiver.<方法名>(參數(shù)列表)
println("WWJJFF".padding(5, '_'))
println("_".times(10))
fun String.padding(cont: Int, char: Char = ' '): String {
val padding = (1..cont).joinToString("") { char.toString() }
return "${padding}${this}${padding}"
}
fun String.times(count: Int): String {
return (1..count).joinToString("") { this }
}
除了給類增加擴展方法之外,還可以給類增加擴展屬性
如果類中沒有接收該擴展屬性的屬性,則只能定義成val形式的 只取返回值
class PoorGuy
//類的屬性=backing filed +getter +setter
//增加擴展屬性money類型為Double
val PoorGuy.money: Double
get() {
return 1.0
}
val guy: PoorGuy = PoorGuy()
val aa = PoorGuy::money//正常的屬性引用
val bb = guy::money//具體對象的屬性引用
注意:接口中可以定義屬性,但是該屬性不能有backing filed;因為接口不能存儲東西,只能定義行為,接口中可以默認實現(xiàn),只能是行為,不能持有狀態(tài)
擴展方法的類型和普通方法的類型一樣
3,空類型安全
空類型安全:任意類型都有可空和不可空兩種;Kotlin提供了編譯級別的預防.
- 每個方法的返回值或者每個變量在被使用到時如果可為null則編譯器會提示使用該值時需要進行null判斷;
- 如果方法的返回則不可為null,則該使用到時可不進行判斷;
- 如果已經確認可為null返回值的 已經為null,可使用'!!'直接調用
fun getNameNotNull(): String {
return "not Null"
}
fun getNameCanNull(): String? {
return null
}
fun getNameRealOne(): String? {
return "A Real name"
}
fun main(args: Array<String>) {
//不用判斷,因為肯定不為null
println(getNameNotNull().length)
//此時需要判斷,可能為null,若不判斷編譯不過,加?標示不為null時調用.length
//若為為null則返回null
println(getNameCanNull()?.length)
//已經知道了結果肯定不為null,但是此時編譯器不認,需要使用!!告訴
//編譯器我已經確定結果肯定不為null
println(getNameRealOne()!!.length)
val aName: String = getNameCanNull() ?: return
//等同于if (aName==null) return
println(aName.length)
}
任意類型 String Int Any Person等作為變量或者返回值類型時加"?"表示可為空類型,這樣在用到該變量或者返回值時需要進行判斷
例如:
var abc:String?=null
var p:Any?=null
安全訪問和elvis運算符
- "?." 安全訪問:如果變量為null則直接返回null
- "?:" elvis 運算符,如果前面的表達式返回為null 則返回后面的值
val str:String?="Hellos"
var len=str?.length?:0
String?和String是什么關系呢?String是String?的子類
平臺類型
Kotlin在訪問其他語言的對象或者方法時,如果返回String!或者Any!表示,返回的是平臺類型,這個時候需要開發(fā)者自己判斷null or not null
4,智能類型轉換
智能類型轉換:如果通過已知條件判斷出某個類所屬類型,可直接使用某類的特性即可,編譯器會盡可能的推導類型,遠離無用的類型轉換
open class Parent {}
class Child : Parent() {
fun getName(): String {
return "000";
}
}
fun main(args: Array<String>) {
val test: Parent = Child()
if (test is Child) {
//不用在使用時再次進行轉換
println(test.getName())
}
test.getName()
}
智能類型轉換是有作用范圍的,超過作用范圍后其類型還是原來定義的類型
如上例中最后的getName是沒有該方法的
安全類型轉換:在Java中如果類型轉換失敗則會拋出類型轉換異常,Kotlin中也有這種情況,為了避免它,可使用"as?"如果轉換失敗則返回null
open class Parent {}
class Child : Parent() {
fun getName(): String {
return "000";
}
}
fun main(args: Array<String>) {
val test2: Parent = Parent()
//如果轉換失敗則返回null,不會拋出異常
val child: Child? = test2 as? Child
println(child?.getName())
}