1、kotlin 可見(jiàn)性修飾符
Java有四種:
- public:包內(nèi)及包外的任何類(lèi)均可以訪問(wèn)
- protected:包內(nèi)的任何類(lèi),及包外的那些繼承了此類(lèi)的子類(lèi)才能訪問(wèn)
- 默認(rèn):包內(nèi)的任何類(lèi)都可以訪問(wèn)它,包外的任何類(lèi)都不能訪問(wèn)
- private:包內(nèi)包外的任何類(lèi)均不能訪問(wèn)
Kotlin也是有四種:
- public:默認(rèn)值日缨,什么都不寫(xiě)表示是public。
- protected:和Java不同的是,即使在同一個(gè)包內(nèi)眷昆,也不能訪問(wèn)protected方法。比private多了子類(lèi)可以調(diào)用這一范圍汁咏。
- internal:所在的整個(gè) module 可見(jiàn)
- private:只在這個(gè)類(lèi)內(nèi)部可見(jiàn)亚斋。
2、kotlin 主構(gòu)造函數(shù)
主構(gòu)造函數(shù) 寫(xiě)在類(lèi)頭中 如果你不希望別的類(lèi)訪問(wèn)到這個(gè)變量攘滩,可以用private修飾
class Person constructor(firstName: String) {
}
如果主構(gòu)造函數(shù)沒(méi)有注解或可見(jiàn)性說(shuō)明帅刊,則 constructor 關(guān)鍵字是可以省略:
class Person (firstName: String) {
}
如果構(gòu)造函數(shù)有注解或可見(jiàn)性聲明,則 constructor 關(guān)鍵字是不可少的轰驳,并且可見(jiàn)性應(yīng)該在前
class Customer public @inject constructor (name: String) {...}
主構(gòu)造函數(shù)不能包含任意代碼厚掷。初始化代碼可以放在以 init 做前綴的初始化塊內(nèi)
class Person (firstName: String) {
init {
logger,info("Customer initialized with value ${firstName}")
}
}
總結(jié)
- 主構(gòu)造函數(shù) constructor寫(xiě)在類(lèi)頭中 弟灼,沒(méi)有修飾符或者注解修飾可以省略constructor關(guān)鍵字
- 主構(gòu)造函數(shù)中,如果參數(shù)加var會(huì)自動(dòng)生成對(duì)應(yīng)的屬性
- 主構(gòu)造函數(shù)中冒黑,如果你不希望別的類(lèi)訪問(wèn)到這個(gè)變量田绑,可以用private修飾
- init代碼塊也屬于主構(gòu)造器的一部分,也可以引用主構(gòu)造函數(shù)中的變量
- 如果沒(méi)有主構(gòu)造函數(shù)抡爹,也會(huì)隱式地創(chuàng)建一個(gè)無(wú)參構(gòu)造函數(shù)掩驱,
- 創(chuàng)建對(duì)象不需要 new
3、kotlin 次構(gòu)造函數(shù)
類(lèi)也可以有二級(jí)構(gòu)造函數(shù)冬竟,需要加前綴 constructor:
- 次級(jí)構(gòu)造函數(shù)
不能直接將參數(shù)轉(zhuǎn)換為屬性(不能加var)
- 如果有主構(gòu)造器欧穴,那么次構(gòu)造器必須直接或者間接引用到主構(gòu)造器
在同一個(gè)類(lèi)中代理另一個(gè)構(gòu)造函數(shù)使用this
關(guān)鍵字:
class Person(var firstName: String) {
init {
println("Customer initialized with value ${firstName}")
}
//var firstName: String? = null
constructor() : this("Xiao ming")
//不能直接將參數(shù)轉(zhuǎn)換為字段,
constructor(firstName: String, lastName: String) : this(firstName) {
this.lastName = lastName
}
var lastName: String? = null
}
4泵殴、 重寫(xiě)get set方法
聲明一個(gè)屬性的完整語(yǔ)法是
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
其初始器(initializer)涮帘、getter 和 setter 都是可選的。屬性類(lèi)型如果可以從初始器 (或者從其 getter 返回值笑诅,如下文所示)中推斷出來(lái)调缨,也可以省略。
var allByDefault: Int? *錯(cuò)誤:需要顯式初始化器吆你,隱含默認(rèn) getter 和 setter
var initialized = 1 * 類(lèi)型 Int弦叶、默認(rèn) getter 和 setter
在主構(gòu)造函數(shù)中 初始器(initializer) 才可以省略
class User {
constructor(name: String, sex: Int) {
this.name = name
this.sex = sex
}
var name: String? = null
var sex: Int? = null
set(value) {
// 此處 如果調(diào)用 sex 賦值 會(huì)造成死循環(huán) sex=0
if (0 == value) { // 正確
sexStr = "男"
} else {
sexStr = "女11"
}
}
var sexStr: String? = null
// get() {
// // 此處 如果調(diào)用 sexStr 取值 會(huì)造成死循環(huán) if ("".equals(sexStr))
// if (0 == sex) { // 正確
// return "男"
// }
// return "女"
// }
}
一般不需要重寫(xiě)get set方法,在某些特定場(chǎng)景下重寫(xiě)即可妇多,但注意避免死循環(huán)
5伤哺、 繼承
kotlin 中所有的類(lèi)和方法默認(rèn)都是final
,不能直接繼承或者重寫(xiě)者祖,如果要繼承或重寫(xiě)立莉,需要加上open
關(guān)鍵字
open class Parent(var name: String) {
var sex: String? = null
init {
this.name = "人"
}
// 沒(méi)有加open關(guān)鍵字,不能重寫(xiě)
fun showParent() {
}
// 加open關(guān)鍵字可以重寫(xiě)
open fun showSelf() {
}
}
class Child( name: String):Parent (name){
// 沒(méi)有加open關(guān)鍵字咸包,不能重寫(xiě)
// fun showParent(){
//
// }
// 重寫(xiě)加 override 一般寫(xiě)法不換行
override fun showSelf(){
}
}
6桃序、 接口
接口用關(guān)鍵字 interface 來(lái)定義:
個(gè)類(lèi)或?qū)ο罂梢詫?shí)現(xiàn)一個(gè)或多個(gè)接口
interface TestInterface {
//可以在接口中聲明屬性,但屬性必須是抽象的 或 提供訪問(wèn)實(shí)現(xiàn)烂瘫。
//private var name: Int //這種寫(xiě)法錯(cuò)誤
//var name: String? = null //這種寫(xiě)法錯(cuò)誤
var name: String
abstract var sex: Int
fun test()
}
class TestInterfaceImpl(override var name: String, override var sex: Int) : TestInterface {
override fun test() {
println(name+"--"+sex)
}
}
接口中聲明的媒熊,必須是抽象的 或 提供訪問(wèn)實(shí)現(xiàn)
7、 抽象
abstract class A {
//abstract val name: String ? = null 寫(xiě)法錯(cuò)誤
//val name: String ? = null 寫(xiě)法正確
abstract val name: String //寫(xiě)法正確
//抽象類(lèi)里已經(jīng)提供實(shí)現(xiàn)的方法 要想被重寫(xiě)必須加open
open fun test() {
println(name)
}
abstract fun testNobody()
//抽象類(lèi)里的方法,可以不提供提供實(shí)現(xiàn)的時(shí)候需要用abstract關(guān)鍵字來(lái)描述 抽象的方法默認(rèn)是open的
}
class B:A() {
override val name: String=""
override fun test() {
println(name)
}
override fun testNobody(){
}
}
抽象類(lèi)里,抽象的方法默認(rèn)是open的坟比,非抽象方法是final的
可以不提供提供實(shí)現(xiàn)的時(shí)候需要用abstract關(guān)鍵字來(lái)描述
抽象類(lèi)里 可以有屬性芦鳍,屬性必須是非null的或者抽象的
8、可以使用默認(rèn)參數(shù)來(lái)實(shí)現(xiàn)java重載類(lèi)似的功能
//函數(shù)參數(shù)可以設(shè)置默認(rèn)值,當(dāng)參數(shù)被忽略時(shí)會(huì)使用默認(rèn)值葛账。這樣相比其他語(yǔ)言可以減少重載
fun reformat(name: String, sex: Boolean = true,age: Int= 18) {
}
reformat("TOM")
reformat("Tom", true, 18)
9柠衅、data
在Kotlin中一些只保存數(shù)據(jù)的類(lèi),稱(chēng)為數(shù)據(jù)類(lèi)(data class),
為了確保自動(dòng)生成的代碼一致性和有意義,數(shù)據(jù)類(lèi)(data class)必須滿足以下要求:
- 主構(gòu)造函數(shù)至少有一個(gè)參數(shù);
- 主構(gòu)造函數(shù)的所有參數(shù)需標(biāo)記為val 或 var;
- 數(shù)據(jù)類(lèi)不能是抽象、開(kāi)放籍琳、密封或者內(nèi)部的;
編譯器會(huì)為數(shù)據(jù)類(lèi)(data class)自動(dòng)生成以下函數(shù):
- equals()/hashCode()
- toString() 默認(rèn)輸出"User(name=John, age=42)"
- componentN() 按聲明順序?qū)?yīng)于所有屬性
- copy()
10菲宴、copy
- 當(dāng)要復(fù)制一個(gè)對(duì)象,只改變一些屬性,但其余不變,copy()就是為此而生:
data class DataUser(val name: String, val age: Int)
val u = DataUser(name = "lioil", age = 1)
val u1 = u.copy("win") //傳遞第一參數(shù),第二參數(shù)默認(rèn)
val u2 = u.copy("win",2) //傳遞所有參數(shù)
val u3 = u.copy(age = 3) //命名參數(shù),傳遞指定參數(shù)
println("$u1,$u2,$u3")
DataUser(name=win, age=1),DataUser(name=win, age=2),DataUser(name=lioil, age=3)
11贷祈、apply
- apply函數(shù),在函數(shù)范圍內(nèi)喝峦,可以任意調(diào)用該對(duì)象的任意方法势誊,并返回該對(duì)象
data class DataUser(val name: String, var age: Int){
fun test (){
println("test")
}
}
val u = DataUser(name = "lioil", age = 1)
val u1 = u.apply {
age = 15
test()
}
println("$u1")
mame 是無(wú)法修改的 因?yàn)槭莢al