100-Kotlin語言的接口定義
101-Kotlin語言的接口的默認(rèn)實(shí)現(xiàn)
102-Kotlin語言的抽象類學(xué)習(xí)
103-Kotlin語言的定義泛型類
104-Kotlin語言的泛型函數(shù)學(xué)習(xí)
105-Kotlin語言的泛型變換實(shí)戰(zhàn)
106-Kotlin語言的泛型類型約束學(xué)習(xí)
107-Kotlin語言的vararg關(guān)鍵字(動態(tài)參數(shù))
108-Kotlin語言的[ ]操作符學(xué)習(xí)
109-Kotlin語言的out-協(xié)變學(xué)習(xí)
110-Kotlin語言的in-逆變學(xué)習(xí)
111-Kotlin語言中使用in和out
112-Kotlin語言的reified關(guān)鍵字學(xué)習(xí)
113-Kotlin語言的定義擴(kuò)展函數(shù)學(xué)習(xí)
114-Kotlin語言的超類上定義擴(kuò)展函數(shù)
115-Kotlin語言的泛型擴(kuò)展函數(shù)
116-Kotlin語言的標(biāo)準(zhǔn)函數(shù)與泛型擴(kuò)展函數(shù)
117-Kotlin語言的擴(kuò)展屬性
118-Kotlin語言的可空類型擴(kuò)展函數(shù)
119-Kotlin語言的infix關(guān)鍵字
120-Kotlin語言的定義擴(kuò)展文件
121-Kotlin語言的重命名擴(kuò)展學(xué)習(xí)
122-Kotlin語言的apply函數(shù)詳解
123-Kotlin語言的DSL學(xué)習(xí)
124-Kotlin語言的變換函數(shù)-map
125-Kotlin語言的變換函數(shù)-flatMap
126-Kotlin語言的過濾函數(shù)-filter
127-Kotlin語言的合并函數(shù)-zip
128-Kotlin語言中使用函數(shù)式編程
129-Kotlin語言的互操作性與可空性
130-Kotlin語言的單例模式
131-注解@JvmName與Kotlin
132-注解@JvmField與Kotlin
133-注解@JvmOverloads與Kotlin
134-注解@JvmStatic與Kotlin關(guān)系
135-手寫事件變換操作符之create
136-手寫事件變換操作符之中轉(zhuǎn)站
137-手寫事件變換操作符之map
138-手寫事件變換操作符之總結(jié)與簡化代碼
139-手寫事件變換操作符之observer
140-手寫事件變換操作符之Rx操作符總結(jié)
interface
interface TUSB{
var usbVersion:String
var usbDevice:String
fun insertUsb():String
}
class Mouse():TUSB{
override var usbVersion: String=""
get() = "USB 3.0"
set(value) {
field = value
}
override var usbDevice: String=""
get() {
println("獲取了${field} 的值")
return field
}
set(value) {
field = value
println("設(shè)置了 ${field} 的值")
}
override fun insertUsb(): String {
return "Mouse ${usbVersion},${usbDevice}"
}
}
class KeyBoard(override var usbVersion: String, override var usbDevice: String):TUSB{
override fun insertUsb(): String {
return "KeyBoard ${usbVersion},${usbDevice}"
}
}
fun main() {
val usb1:TUSB = Mouse()
usb1.usbVersion = "USB 3.1"
usb1.usbDevice = "AAA"
println(usb1.insertUsb())
val usb2:TUSB = KeyBoard("USB 3.0","Keyboard")
println(usb2.insertUsb())
}
1.接口里面的所有成員 和 接口本身 都是 public open 的,所以不需要open,這個是接口的特殊
2.接口不能有主構(gòu)造
3.實(shí)現(xiàn)類不僅僅要重寫接口的函數(shù),也要重寫 接口的成員
4.接口實(shí)現(xiàn)代碼區(qū)域,全部都要增加 override 關(guān)鍵字來修飾
abstract
demo
abstract class BaseActivity{
fun onCreate(){
setContentView(getLayout());
initView()
initData()
}
abstract fun getLayout():Int
private fun setContentView(id:Int) = println("setContentView ${id}...")
abstract fun initView()
abstract fun initData()
}
class MainActivity(): BaseActivity() {
override fun getLayout(): Int {
println("R.layout.main")
return 1111
}
override fun initView() {
println("Main initView")
}
override fun initData() {
println("Main initData")
}
fun show() = super.onCreate()
}
fun main() {
MainActivity().show()
}
泛型
class OutShow<T>(val obj:T){
fun show() = println("$obj")
}
data class Stu(val name:String,val age:Int)
data class Teacher(val name:String,val age:Int)
fun main() {
OutShow(Stu("zhangsan",16)).show()
OutShow(Stu("zcwfeng",36)).show()
OutShow(String("Hello world".toByteArray())).show()
}
fun <B> showme(obj:B){
val r= obj?.also {
println("it is $obj")
}?: println("it is null...")
}
showme(Stu("zhangsan",16))
showme(null)
Map 轉(zhuǎn)換,(模仿RxJava操作符)
class MapClass<T>(val isMap: Boolean = false, val input: T) {
inline fun <R> map(mapAction: (T) -> R): R? = mapAction(input).takeIf { isMap }
}
inline fun <I,O> map(inputValue: I, isMap: Boolean = true, mapAction: (I) -> O): O? {
return if (isMap) mapAction(inputValue) else null
}
fun main() {
val test: String? = MapClass(isMap = true, 2222).map {
it.toString()
}
val test2: Int? = MapClass(isMap = true, 2222).map {
it
}
val teacher: Teacher? = MapClass(isMap = true, Stu("zcwfeng", 22)).map {
Teacher(it.name, it.age)
}
println(test)
println(teacher is Teacher)
//map 仿 RxJava 變換
val result = map(123){
it.toString()
"map wrapper${it}"
}
println(result)
}
泛型限定
open class MyAnyClass(name:String)
open class PersonClass(name: String):MyAnyClass(name)
class StudentClass(name: String):PersonClass(name)
class TeacherClass(name: String):PersonClass(name)
class DogClass(name: String)
// java T extends PersonClass
class PResultClass<T/*:PersonClass*/> (val inputValue:T,var isR:Boolean = true){
fun getObj() = inputValue.takeIf { isR }
}
fun main() {
val myAny = PResultClass(MyAnyClass("zcwfeng")).getObj()
val per = PResultClass(PersonClass("zcwfeng")).getObj()
val teacher = PResultClass(TeacherClass("zcwfeng")).getObj()
val stu = PResultClass(StudentClass("zcwfeng")).getObj()
val dog = PResultClass(DogClass("zcwfeng")).getObj()
println("myAny=${myAny},\nper=${per},\nteacher=${teacher},\nstu=${stu},\ndog=$dog")
}
vararg關(guān)鍵字(動態(tài)參數(shù))
class T11<T>(vararg objects: T, val isMap: Boolean = true) {
// out 不能修改只能讀取
val objectArray: Array<out T> = objects
// index 下對應(yīng)的對象
fun showObj(index: Int): T? = objectArray[index].takeIf { isMap }
//
fun <O> mapObj(index: Int, mapAction: (T?) -> O): O? = mapAction(objectArray[index].takeIf { isMap })
}
fun main() {
// 真實(shí)數(shù)據(jù)類型 {Comparable<*> & java.io.Serializable}
val values = T11("zwfeng", false, 12345, 12345.66, null, 'C', isMap = true)
for (i in 0..5) {
println(values.showObj(i))
}
println()
val r1 = values.mapObj(0){
it
it.toString()
it.toString().length
}
println("第零個元素的字符串長度是:$r1")
val r2:String? = values.mapObj(2){
"第三個元素$it"
}
println(r2)
val p2 : T11<String> = T11("AAA", "BBB", "CCC", isMap = true)
val r3 = p2.mapObj(0){
it
it.toString()
"String? 類型的 $it"
}
println(r3)
}
獲取不方便只能get(index),進(jìn)行一個操作符重栽使用xxx[index],并且列出返回類型所有可能
class T13<INPUT>(vararg objects: INPUT, val isR: Boolean = true) {
private val objarray: Array<out INPUT> = objects
fun getR1(): Array<out INPUT>? = objarray.takeIf { isR }
fun getR2(): Any = objarray.takeIf { isR } ?: "you null"
fun getR3(): Any? = objarray.takeIf { isR } ?: null
fun getR4(index: Int): INPUT? = objarray[index].takeIf { isR } ?: null
fun getR5(index: Int): Any? = objarray[index].takeIf { isR } ?: "AAAA"
operator fun get(index: Int): INPUT? = objarray[index].takeIf { isR }
}
fun <INPUT> inputFun(value: INPUT) {
println((value as String?)?.length)
}
fun main() {
inputFun("aaaaa")
inputFun(null)
val t = T13("aa","bb","cc","dd",null)
println(t[1])
println(t[3])
println(t[4])
}
out-協(xié)變,in-逆變
interface Producer<out T> {
fun produce():T
// fun consume(item:T)
}
interface Consumer<in T>{
// fun produce():T
fun consume(item:T)
}
interface ProducerConsumer<T>{
fun produce():T
fun consume(item:T)
}
- 協(xié)變 [out T 此泛型能夠被獲取 讀取 所以是out]
- 逆變 [in T 此泛型只能被修改 更新 所以是in]
沒有進(jìn)行out 和 in 限制的借口,沒有限制
open class Animal // 動物
open class Humanity : Animal() // 人類
open class Man : Humanity() // 男人
open class WoMan : Humanity() // 女人
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 只管生產(chǎn)者
class ProducerClass1 : Producer<Animal> {
override fun produce(): Animal {
println("生產(chǎn)者 Animal")
return Animal()
}
}
class ProducerClass2 : Producer<Humanity> {
override fun produce(): Humanity {
println("生產(chǎn)者 Humanity")
return Humanity()
}
}
class ProducerClass3 : Producer<Man> {
override fun produce(): Man {
println("生產(chǎn)者 Man")
return Man()
}
}
class ProducerClass4 : Producer<WoMan> {
override fun produce(): WoMan {
println("生產(chǎn)者 WoMan")
return WoMan()
}
}
fun main() {
val p1 : Producer<Animal> = ProducerClass1()
val p2 : Producer<Animal> = ProducerClass2()
val p3 : Producer<Animal> = ProducerClass3()
val p4 : Producer<Animal> = ProducerClass4()
}
- 去掉
out TProducerClass1他本來就是 傳遞 Animal ,當(dāng)然是可以的
ProducerClass2,ProducerClass3,ProducerClass4,因?yàn)閛ut, 才是被允許的
泛型規(guī)則默認(rèn)情況下是:泛型的子類對象 不可以賦值給 泛型的父類對象,泛型具體處的子類對象 不可以賦值給 泛型聲明處的父類對象
out: 泛型的子類對象 可以賦值給 泛型的父類對象
out: 泛型具體出的子類對象 可以賦值給 泛型聲明處的父類對象
協(xié)變:父類 泛型聲明處 可以接收 子類 泛型具體處
class ConsumerClass1 : Consumer<Animal> {
override fun consume(item: Animal) {
println("消費(fèi)者 Animal")
}
}
class ConsumerClass2 : Consumer<Humanity> {
override fun consume(item: Humanity) {
println("消費(fèi)者 Humanity")
}
}
class ConsumerClass3 : Consumer<Man> {
override fun consume(item: Man) {
println("消費(fèi)者 Man")
}
}
class ConsumerrClass4 : Consumer<WoMan> {
override fun consume(item: WoMan) {
println("消費(fèi)者 WoMan")
}
}
fun main() {
val p1 : Consumer<Man> = ConsumerClass1()
val p2 : Consumer<WoMan> = ConsumerClass2()
}
- ConsumerClass1,ConsumerClass2,因?yàn)閕n 才可以
默認(rèn)情況下: 泛型具體實(shí)現(xiàn)處的父類 是不可以賦值給 泛型聲明處的子類的
in:泛型具體出的父類 是可以賦值給 泛型聲明處的子類的
逆變:子類 泛型聲明處 可以接收 父類 泛型具體處
協(xié)變:out 父類 = 子類
逆變:in 子類 = 父類
// CharSequence父類 String子類
// 泛型默認(rèn)情況下是:泛型的子類對象 不可以賦值給 泛型的父類對象
// List<CharSequence> list1 = new ArrayList<String>();
List<? extends CharSequence> list2 = new ArrayList<String>();
// 泛型默認(rèn)情況下是:泛型的父類對象 不可以賦值給 泛型的子類對象
// List<String> list3 = new ArrayList<CharSequence>();
List<? super String> list4 = new ArrayList<CharSequence>();
- ? super T 就相當(dāng)于 KT里面的in,所以才可以 泛型父類對象 賦值給 泛型子類對象
? extends T 就相當(dāng)于 KT里面的out,所以才可以 泛型子類對象 賦值給 泛型父類對象
reifield
通過一個例子:默認(rèn)隨機(jī)輸出一個對象,如果此對象和用戶指定的對象不一致,我們就啟用備用對象,否則就直接返回對象
data class ObjectClass1(val name: String, val age: Int, val study: String)
data class ObjectClass2(val name: String, val age: Int, val study: String)
data class ObjectClass3(val name: String, val age: Int, val study: String)
inline fun <reified T> randomOrDefault(defaultAction: () -> T): T? {
val objList: List<Any> = listOf(
ObjectClass1("obj1 李四", 22, "學(xué)習(xí)C"),
ObjectClass2("obj2 王五", 23, "學(xué)習(xí)C++"),
ObjectClass3("obj3 趙六", 24, "學(xué)習(xí)C#")
)
val randomObj = objList.shuffled().first()
println("您隨機(jī)產(chǎn)生的對象 幸運(yùn)兒是:$randomObj")
return randomObj.takeIf { it is T } as T?
?: defaultAction()
}
fun main() {
val finalResult = randomOrDefault<ObjectClass1> {
println("由于隨機(jī)產(chǎn)生的對象 和 我們指定的ObjectClass1不一致,所以啟用備用對象")
ObjectClass1("備用 obj1 李四", 22, "學(xué)習(xí)C") // 最后一行的返回
}
println("客戶端最終結(jié)果:$finalResult")
}
reified 前提必須是inline函數(shù)
泛型it is T判斷必須是 reified 控制才可使用
擴(kuò)展函數(shù)-擴(kuò)展屬性
fun String.addAction(number:Int) = this + "@".repeat(number)
fun String.showstr() = print(this)
fun main() {
"zcwfeng".addAction(3).showstr()
}
超類擴(kuò)展,鏈?zhǔn)秸{(diào)用擴(kuò)展
data class ResponseData(val name:String,val age:Int)
fun Any.showContentPrint() = println("擴(kuò)展內(nèi)容 $this")
fun Any.showContentPrint2():Any{
println("擴(kuò)展內(nèi)容2 $this")
return this
}
fun main() {
"zcwfeng".showContentPrint()
123.4.showContentPrint()
ResponseData("aaa",111).showContentPrint().showContentPrint()
ResponseData("aaa",111).showContentPrint().showContentPrint2()
ResponseData("aaa",111).showContentPrint2().showContentPrint2()
}
泛型擴(kuò)展函數(shù)
fun <T> T.showContent() = println(if (this is String) "字符串類型:length$length" else "非String,內(nèi)容:$this" )
fun <T> T.showCallTime() = println("call time:${System.currentTimeMillis()}")
fun test(){}
...
fun main() {
"zcwfeng".showContent()
123.4.showContent()
ResponseData("aaa",111).showContent()
test().showContent().showCallTime()
...
}
查看模擬官方擴(kuò)展函數(shù)原理
let 內(nèi)置函數(shù)
private inline fun <I,O> I.mLet(lambda:(I)->O) = lambda(this)
調(diào)用
val a:String = "".mLet {
"aaa"
false
"de"
it
}
最后一行返回是本身,持有it,高階函數(shù)用inline 優(yōu)化lambda
系統(tǒng)內(nèi)置函數(shù)
also,apply,let,run,with
擴(kuò)展屬性,
val String.myInfo: String
get() = "調(diào)用時間${System.currentTimeMillis()},當(dāng)前內(nèi)容$this,長度 $length"
測試擴(kuò)展屬性,擴(kuò)展函數(shù)輔助:
"demo".myInfo.showstr()
可空類型擴(kuò)展 String 和 String?是不一樣的
fun String?.outputStringValue() = println(this ?: "null")
fun String?.outputStringValue2():String? = this
infix 中綴表達(dá)式
private infix fun<C,D> C.go(c:D){
println("第一個內(nèi)容$this")
println("第二個內(nèi)容$c")
}
"aaa".go("bbbbb")
"aaa" go "bbbbbb"
借鑒C++的一種簡略語法中綴表達(dá)式
- 必須配合函數(shù)擴(kuò)展使用
- 需要傳遞參數(shù)
擴(kuò)展文件
// 添加一種能力,擴(kuò)展文件,擴(kuò)平臺和應(yīng)用
// Demo Use
// Java --> ExtOptKt.randomItemValue(mFragments);
// kotlin --->list.randowmIemValue()
public fun<E> Iterable<E>.randomItemValue() = println(this.shuffled().first())
// 使用對比
val list = listOf("張三","zcwfeng","David")
val set = setOf(112.33,3333,4444)
println(list.shuffled().first())
println(set.shuffled().first())
println(list.randomItemValue())
工具類放在一個擴(kuò)展文件,這樣這個類所有項(xiàng)目都可以用
可以重命名擴(kuò)展,小技巧
import s5.ext.randomItemValue as itemRandom
// randomItemValue 可以用 itemRandom 代替
println(list.itemRandom())
apply 原理
private inline fun <INPUT> INPUT.mApply(lambda: INPUT.() -> Unit):INPUT {
// lambda(this)
lambda()
return this
}
lambda: INPUT.() -> Unit 目的是讓我們的擴(kuò)展函數(shù)mApply 持有this,永遠(yuǎn)返回本身,支持鏈?zhǔn)秸{(diào)用
DSL-Domain Special Language
class Context {
val info = "我是 zcwfeng DSL"
val name = "DDDD"
fun toast(str:String) = println("str is:$str")
}
inline fun Context.apply5(lambda:Context.(String)->Unit):Context{
lambda(info)
return this
}
fun main() {
val context = Context().apply5 {
println("it is $it,this is $this")
toast("aaaa")
toast(it)
toast(name)
}
println(context)
}
小DSL語法:定義輸入輸出
- 定義lambda規(guī)則,輸入必須是Context這個類,才能調(diào)用apply5,同事持有it和this
- 定義lambda規(guī)則,輸出必須是Context這個類
在看一個例子
inline fun File.applyFile(lambda: (String, String?) -> Unit): File {
setWritable(true)
setReadable(true)
lambda(name, readLines()[0])
return this
}
val file = File("/Users/zcwfeng/Downloads/weimiao.html").applyFile { a, b ->
println("路徑$a,內(nèi)容:$b")
true
}.applyFile { s, d -> }
println("file:$file")
map,flatMap
val list = listOf("aa","bb","cc")
val list2 = list.map {
"[$it]"
}.map {
"[$it,文字長度:${it.length}]"
}
println(list2)
val list = listOf("aa","bb","cc")
val list2 = list.map {
"/$it/"
}.map {
"--$it---文字長度:${it.length}---"
}.flatMap {
println()
listOf("$it 學(xué)習(xí)C++","$it 學(xué)習(xí)Java","$it 學(xué)習(xí)Kotlin")
}
println(list2)
map 原理: 匿名函數(shù) 最后一行的返回值 加入一個新的集合,新集合的泛型是R,并且返回新集合
flatMap 原理:匿名函數(shù) 最后一行的返回值(又是一個集合listOf(......)) 加入一個新的集合,新集合的泛型是R,并且返回新集合
filter
fun main() {
val nameLists = listOf(
listOf("黃曉明", "李連杰", "李小龍"),
listOf("劉軍", "李元霸", "劉明"),
listOf("劉俊", "黃家駒", "黃飛鴻")
)
nameLists.map {
println(it)
}
println()
nameLists.flatMap {
println(it)
listOf("")
}
println()
nameLists.flatMap { it ->
it.filter {
println("$it filter")
true
}
}.map {
println("$it ")
}
println()
nameLists.map {
it.filter {
// false
true
}
}.map {
print("$it ")
}
println()
println()
nameLists.flatMap {
it.filter {
true
// false
}
}.map {
println("$it ")
}
println()
nameLists.flatMap {
it.filter {
it.contains("黃")
}
}.map {
println("$it ")
}
}
filter 原理:filter {true,false} true他會加入到新的集合 進(jìn)行組裝新集合 返回, 否則false,過濾掉,不加入,返回空集合
zip
fun main() {
val names = listOf("zcwfeng","david","luna")
val ages = listOf(11,22,33)
val zip:List<Pair<String,Int>> = names.zip(ages)
println(zip)
println(zip.toMap())
println(zip.toMutableList())
println(zip.toMutableSet())
zip.forEach{ it ->
println("name->${it.first},age->${it.second}")
}
zip.toMap().forEach { (k, v) ->
println("name->$k,age->$v")
}
zip.toMap().forEach{
println("name->${it.key},age->${it.value}")
}
}
zip原理:就是把 第一個集合 和 第二個集合 合并起來,創(chuàng)建新的集合,并返回
對比RxJava操作符zip類似功能
Java 和 Kotlin的調(diào)用,注解
@file:JvmName("Stus")
package s5
//Java 調(diào)用測試
fun getStudentInfo(name:String) = println("$name is ok")
Java Call
public static void main(String[] args) {
// Test21Kt.getStudentInfo("zcwfeng");
Stus.getStudentInfo("zcwfeng");
}
@file:JvmName("Stus") 必須卸載package之前, 調(diào)用的時候編譯器默認(rèn)會更改名字 Test21Kt->Stus
class PersonTest{
@JvmField
val names = listOf("abc","eee","fff")
}
java Call
PersonTest personTest = new PersonTest();
// personTest.getNames();
for (String name:personTest.names){
System.out.println(name);
}
@JvmField 修飾之后,java就可以直接訪問names. 不必在使用getNames
fun show(msg:String,code:Int = 20,name:String = "abc"){
println("show")
}
@JvmOverloads
fun toast(msg:String,code:Int = 20,name:String = "abc"){
println("show")
}
// 不能和Kt一樣用默認(rèn)參數(shù)
// Test22Kt.show("zcwfeng");
Test22Kt.toast("zcwfeng");
@JvmOverloads 可以讓java想kotlin一樣可以調(diào)用默認(rèn)參數(shù)的函數(shù)
class GoStudy{
companion object{
@JvmField
val TARGET = "清華北大"
@JvmStatic
fun showAction() = println("我要 到 $TARGET 上學(xué)")
}
}
// System.out.println(GoStudy.Companion.getTARGET());
// GoStudy.Companion.showAction();
System.out.println(GoStudy.TARGET);
GoStudy.showAction();
加上 @JvmField 和 @JvmStatic之前,只能像注釋代碼一樣調(diào)用
加上之后,就可以和Kotlin一樣調(diào)companion object了
Kotlin 模仿RxJava create操作符手動實(shí)現(xiàn)
// 模擬rxjava create,輸入沒有任何參數(shù),輸出萬能類型,
inline fun <OUTPUT> create(action: () -> OUTPUT): RxJavaCoreClassObject<OUTPUT> = RxJavaCoreClassObject(action())
// 保存Object,信息是value====create最后一行信息的返回
class RxJavaCoreClassObject<T>(val value: T)
inline fun<T,O> RxJavaCoreClassObject<T>.map(mAction:T.()->O) = RxJavaCoreClassObject(mAction(value))
// 只需要把輸入內(nèi)容輸出就行
inline fun<T>RxJavaCoreClassObject<T>.observer(observerAction:T.()->Unit) = observerAction(value)
fun main() {
create {
"derry"
123
true
"AAAAA"
}.map{
"your value is $this"
}.map {
"[$this]"
}.map {
"@@$this@@"
}.map {
println(this)
}
}
一個有意思的lambda
val fan: (String) -> (String) -> (Boolean) -> (Int) ->(String)-> Int = {
{
{
{
{
99
}
}
}
}
}
println(fan("AAA")("bbb")(false)(44)("aaaa"))