Kotlin 小细节记录(6)
100-Kotlin语言的接口定义
101-Kotlin语言的接口的默认实现
102-Kotlin语言的抽象类学习
103-Kotlin语言的定义泛型类
104-Kotlin语言的泛型函数学习
105-Kotlin语言的泛型变换实战
106-Kotlin语言的泛型类型约束学习
107-Kotlin语言的vararg关键字(动态参数)
108-Kotlin语言的[ ]操作符学习
109-Kotlin语言的out-协变学习
110-Kotlin语言的in-逆变学习
111-Kotlin语言中使用in和out
112-Kotlin语言的reified关键字学习
113-Kotlin语言的定义扩展函数学习
114-Kotlin语言的超类上定义扩展函数
115-Kotlin语言的泛型扩展函数
116-Kotlin语言的标准函数与泛型扩展函数
117-Kotlin语言的扩展属性
118-Kotlin语言的可空类型扩展函数
119-Kotlin语言的infix关键字
120-Kotlin语言的定义扩展文件
121-Kotlin语言的重命名扩展学习
122-Kotlin语言的apply函数详解
123-Kotlin语言的DSL学习
124-Kotlin语言的变换函数-map
125-Kotlin语言的变换函数-flatMap
126-Kotlin语言的过滤函数-filter
127-Kotlin语言的合并函数-zip
128-Kotlin语言中使用函数式编程
129-Kotlin语言的互操作性与可空性
130-Kotlin语言的单例模式
131-注解@JvmName与Kotlin
132-注解@JvmField与Kotlin
133-注解@JvmOverloads与Kotlin
134-注解@JvmStatic与Kotlin关系
135-手写事件变换操作符之create
136-手写事件变换操作符之中转站
137-手写事件变换操作符之map
138-手写事件变换操作符之总结与简化代码
139-手写事件变换操作符之observer
140-手写事件变换操作符之Rx操作符总结
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("设置了 ${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.接口不能有主构造
3.实现类不仅仅要重写接口的函数,也要重写 接口的成员
4.接口实现代码区域,全部都要增加 override 关键字来修饰
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 转换,(模仿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关键字(动态参数)
class T11<T>(vararg objects: T, val isMap: Boolean = true) {
// out 不能修改只能读取
val objectArray: Array<out T> = objects
// index 下对应的对象
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() {
// 真实数据类型 {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),进行一个操作符重栽使用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-协变,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)
}
- 协变 [out T 此泛型能够被获取 读取 所以是out]
- 逆变 [in T 此泛型只能被修改 更新 所以是in]
没有进行out 和 in 限制的借口,没有限制
open class Animal // 动物
open class Humanity : Animal() // 人类
open class Man : Humanity() // 男人
open class WoMan : Humanity() // 女人
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 只管生产者
class ProducerClass1 : Producer<Animal> {
override fun produce(): Animal {
println("生产者 Animal")
return Animal()
}
}
class ProducerClass2 : Producer<Humanity> {
override fun produce(): Humanity {
println("生产者 Humanity")
return Humanity()
}
}
class ProducerClass3 : Producer<Man> {
override fun produce(): Man {
println("生产者 Man")
return Man()
}
}
class ProducerClass4 : Producer<WoMan> {
override fun produce(): WoMan {
println("生产者 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 T
ProducerClass1他本来就是 传递 Animal ,当然是可以的
ProducerClass2,ProducerClass3,ProducerClass4,因为out, 才是被允许的
泛型规则默认情况下是:泛型的子类对象 不可以赋值给 泛型的父类对象,泛型具体处的子类对象 不可以赋值给 泛型声明处的父类对象
out: 泛型的子类对象 可以赋值给 泛型的父类对象
out: 泛型具体出的子类对象 可以赋值给 泛型声明处的父类对象
协变:父类 泛型声明处 可以接收 子类 泛型具体处
class ConsumerClass1 : Consumer<Animal> {
override fun consume(item: Animal) {
println("消费者 Animal")
}
}
class ConsumerClass2 : Consumer<Humanity> {
override fun consume(item: Humanity) {
println("消费者 Humanity")
}
}
class ConsumerClass3 : Consumer<Man> {
override fun consume(item: Man) {
println("消费者 Man")
}
}
class ConsumerrClass4 : Consumer<WoMan> {
override fun consume(item: WoMan) {
println("消费者 WoMan")
}
}
fun main() {
val p1 : Consumer<Man> = ConsumerClass1()
val p2 : Consumer<WoMan> = ConsumerClass2()
}
- ConsumerClass1,ConsumerClass2,因为in 才可以
默认情况下: 泛型具体实现处的父类 是不可以赋值给 泛型声明处的子类的
in:泛型具体出的父类 是可以赋值给 泛型声明处的子类的
逆变:子类 泛型声明处 可以接收 父类 泛型具体处
协变:out 父类 = 子类
逆变:in 子类 = 父类
// CharSequence父类 String子类
// 泛型默认情况下是:泛型的子类对象 不可以赋值给 泛型的父类对象
// List<CharSequence> list1 = new ArrayList<String>();
List<? extends CharSequence> list2 = new ArrayList<String>();
// 泛型默认情况下是:泛型的父类对象 不可以赋值给 泛型的子类对象
// List<String> list3 = new ArrayList<CharSequence>();
List<? super String> list4 = new ArrayList<CharSequence>();
- ? super T 就相当于 KT里面的in,所以才可以 泛型父类对象 赋值给 泛型子类对象
? extends T 就相当于 KT里面的out,所以才可以 泛型子类对象 赋值给 泛型父类对象
reifield
通过一个例子:默认随机输出一个对象,如果此对象和用户指定的对象不一致,我们就启用备用对象,否则就直接返回对象
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, "学习C"),
ObjectClass2("obj2 王五", 23, "学习C++"),
ObjectClass3("obj3 赵六", 24, "学习C#")
)
val randomObj = objList.shuffled().first()
println("您随机产生的对象 幸运儿是:$randomObj")
return randomObj.takeIf { it is T } as T?
?: defaultAction()
}
fun main() {
val finalResult = randomOrDefault<ObjectClass1> {
println("由于随机产生的对象 和 我们指定的ObjectClass1不一致,所以启用备用对象")
ObjectClass1("备用 obj1 李四", 22, "学习C") // 最后一行的返回
}
println("客户端最终结果:$finalResult")
}
reified 前提必须是inline函数
泛型it is T
判断必须是 reified 控制才可使用
扩展函数-扩展属性
fun String.addAction(number:Int) = this + "@".repeat(number)
fun String.showstr() = print(this)
fun main() {
"zcwfeng".addAction(3).showstr()
}
超类扩展,链式调用扩展
data class ResponseData(val name:String,val age:Int)
fun Any.showContentPrint() = println("扩展内容 $this")
fun Any.showContentPrint2():Any{
println("扩展内容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()
}
泛型扩展函数
fun <T> T.showContent() = println(if (this is String) "字符串类型:length$length" else "非String,内容:$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()
...
}
查看模拟官方扩展函数原理
let 内置函数
private inline fun <I,O> I.mLet(lambda:(I)->O) = lambda(this)
调用
val a:String = "".mLet {
"aaa"
false
"de"
it
}
最后一行返回是本身,持有it,高阶函数用inline 优化lambda
系统内置函数
also,apply,let,run,with
扩展属性,
val String.myInfo: String
get() = "调用时间${System.currentTimeMillis()},当前内容$this,长度 $length"
测试扩展属性,扩展函数辅助:
"demo".myInfo.showstr()
可空类型扩展 String 和 String?是不一样的
fun String?.outputStringValue() = println(this ?: "null")
fun String?.outputStringValue2():String? = this
infix 中缀表达式
private infix fun<C,D> C.go(c:D){
println("第一个内容$this")
println("第二个内容$c")
}
"aaa".go("bbbbb")
"aaa" go "bbbbbb"
借鉴C++的一种简略语法中缀表达式
- 必须配合函数扩展使用
- 需要传递参数
扩展文件
// 添加一种能力,扩展文件,扩平台和应用
// 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())
工具类放在一个扩展文件,这样这个类所有项目都可以用
可以重命名扩展,小技巧
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 目的是让我们的扩展函数mApply 持有this,永远返回本身,支持链式调用
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规则,输入必须是Context这个类,才能调用apply5,同事持有it和this
- 定义lambda规则,输出必须是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,内容:$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 学习C++","$it 学习Java","$it 学习Kotlin")
}
println(list2)
map 原理: 匿名函数 最后一行的返回值 加入一个新的集合,新集合的泛型是R,并且返回新集合
flatMap 原理:匿名函数 最后一行的返回值(又是一个集合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他会加入到新的集合 进行组装新集合 返回, 否则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原理:就是把 第一个集合 和 第二个集合 合并起来,创建新的集合,并返回
对比RxJava操作符zip类似功能
Java 和 Kotlin的调用,注解
@file:JvmName("Stus")
package s5
//Java 调用测试
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之前, 调用的时候编译器默认会更改名字 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一样用默认参数
// Test22Kt.show("zcwfeng");
Test22Kt.toast("zcwfeng");
@JvmOverloads 可以让java想kotlin一样可以调用默认参数的函数
class GoStudy{
companion object{
@JvmField
val TARGET = "清华北大"
@JvmStatic
fun showAction() = println("我要 到 $TARGET 上学")
}
}
// System.out.println(GoStudy.Companion.getTARGET());
// GoStudy.Companion.showAction();
System.out.println(GoStudy.TARGET);
GoStudy.showAction();
加上 @JvmField 和 @JvmStatic之前,只能像注释代码一样调用
加上之后,就可以和Kotlin一样调companion object了
Kotlin 模仿RxJava create操作符手动实现
// 模拟rxjava create,输入没有任何参数,输出万能类型,
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))
// 只需要把输入内容输出就行
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"))