Kotlin细节文章笔记整理更新进度: Kotlin系列 - 基础类型结构细节小结(一)java
open
才能够被继承(kotlin
默认为final
)open
才能够被覆写open
override
关键字abstract class Person(open val age: Int){
abstract fun work()
}
class MaNong(age: Int): Person(age){
override val age: Int
get() = 0
override fun work() {
println("我是码农,我在写代码")
}
}
class Doctor(override val age: Int): Person(age){
override fun work() {
println("我是医生,我在给病人看病")
}
}
fun main(args: Array<String>) {
val person: Person = MaNong(23)
person.work()
println(person.age)
val person2 : Person = Doctor(20)
person2.work()
println(person2.age)
}
-------------------------------------打印出来
我是码农,我在写代码
0
我是医生,我在给病人看病
20
复制代码
by
)接口方法实现交给代理类实现ios
class Manager(diver:Driver): Driver by driver
复制代码
abstract class A{
open fun x(): Int = 5
}
interface B{
fun x(): Int = 1
}
interface C{
fun x(): Int = 0
}
class D(var y: Int = 0): A(), B, C{
override fun x(): Int {
println("call x(): Int in D")
if(y > 0){
return y
}else if(y < -200){
return super<C>.x()
}else if(y < -100){
return super<B>.x()
}else{
return super<A>.x()
}
}
}
复制代码
private protect interanl public
protected
:子类可见 internal
:模块内可见数组
Object
关键字object TestKotlin
------------------------------转化为java代码
public final class TestKotlin {
public static final TestKotlin INSTANCE;
private TestKotlin() {
}
static {
TestKotlin var0 = new TestKotlin();
INSTANCE = var0;
}
}
复制代码
companion object
伴生对象、静态变量成员还有 kotlin
包级成员kotlin
容许不在类下面写成员变量跟方法,称为包级别对象/函数companion object
companion object
与java
的static
静态方法/静态成员的效果相似相同。kotlin
中的静态成员考虑用包级函数、变量代替JvmField
、JvmStatic
、@file:JvmName(本身自定义的类名)
package com.demo.dan.voice
val Str = "包级成员"
fun packFun(): String {
return "包级函数"
}
class TestKotlin {
companion object {
fun compainFun(): String {
return "伴生对象方法"
}
var Str = "伴生对象成员"
}
}
复制代码
在Koltin
与java
中调用bash
//--------------在kotlin中调用
fun main() {
println(Str)//包级成员
println(packFun())//包级函数
TestKotlin.Str
TestKotlin.compainFun()
}
//----------------在java中调用
public class TestJava {
public static void main(String[] args) {
TestKotlin.Companion.compainFun();
TestKotlin.Companion.getStr();
}
复制代码
能够看到上面
java
调用kotlin
的代码并不像咱们java
调用静态对象
同样(中间多了层Companion
)。app上面的
java
调用Kotlin
能够在伴生对象中增长对应的注解: 函数上加@JvmStatic
, 变量上加@JvmField
jvm实现相似调用
java
静态成员/方法maven
class TestKotlin {
companion object {
@JvmStatic
fun compainFun(): String {
return "伴生对象方法"
}
@JvmField
var Str = "伴生对象成员"
}
}
//----------------在java中调用
public class TestJava {
public static void main(String[] args) {
TestKotlin.compainFun();
String str = TestKotlin.Str;
}
}
复制代码
具体的你们能够转一下
kotlin
转java
看一下加了注解跟没有加注解的区别,这里由于篇幅缘由我就不加代码了。ide
这里补充一点: java
怎么调用kotlin
的包级别对象呢???函数
答案:可使用@file:JvmName(本身自定义的类名)
工具
@file:JvmName("TestKotlin1")
package com.demo.dan.imoc_voice
val Str = "包级成员"
fun packFun(): String {
return "包级函数"
}
复制代码
java
调用:
public class TestJava {
public static void main(String[] args) {
TestKotlin1.getStr();
TestKotlin1.packFun();
}
}
复制代码
Overloads
方法重载Jvm
函数签名的概念:函数名、参数列表 (不包含返回值!),也就是当两个方法的方法名跟参数一致的时候,这个函数Jvm
视为一个函数。kotlin
中能够为函数参数设置默认值,来实现重载。//下面两个函数为同一函数签名,函数同样。
fun a():Int{}
fun a():String{}
//方法重载
fun a(s:Stirng){}
fun a(s:String,i:int){}
------------------例子-------------------------------------------------------------
//kotlin提供了默认函数,
//因此上面的方法重载其实能够改为使用默认参数来实现
fun a(s:String = "ss",i:Int){}
fun main() {
a(str ="str")
}
复制代码
java
怎么调用kotlin
的默认参数函数?? 答案:使用 @JvmOverloads
注解//kolin代码----------
@file:JvmName("TestKotlin1")
package com.demo.dan.imoc_voice
@JvmOverloads
fun a(int:Int=1,str: String){}
//java调用------------
public class TestJava {
public static void main(String[] args) {
TestKotlin1.a("dfsdf");
}
}
复制代码
java
方法重载形成得bug
,例如List
List.remove(int)
List.remove(Object)
复制代码
当List里面传入得是int类型得数据,那么你
remove()
传入一个4
那么它是删除第四位数据仍是删除4
这个对象呢?这里它是默认调用了remove(int)
,而remove(Object)
却不会被调用到。
为现有类添加方法、属性
fun X.y():Z{...}
( fun 被扩展类.自定义扩展方法名():返回类型{方法体 }
)var X.m
(var 被扩展类.自定义扩展属性名
) 注意扩展属性不能初始化,相似接口属性(X
为被扩展类)java
调用扩展成员相似于调用静态方法@file:JvmName("TestKotlin1")
package com.demo.dan.voice
// 扩展String 增长multiply方法
fun String.multiply(int: Int): String {
val stringBuilder = StringBuilder()
for (i in 0 until int) {
stringBuilder.append(this)
}
return stringBuilder.toString()
}
//扩展String 增长运算符 -
operator fun String.minus(int: Int): String {
return this.substring(0, length-int+1)
}
//扩展成员变量
val String.a: String
get() = "扩展成员变量"
//扩展成员变量
var String.b: Int
set(value){}
get() = 6
复制代码
kotlin调用
fun main(args: Array<String>) {
println("我是码农".multiply(3))
println("我是码农" - 2)
println("".a)
println("".b)
}
------------打印出来的Log--------------------------
我是码农我是码农我是码农
我是码
扩展成员变量
6
复制代码
java调用
public static void main(String[] args) {
String str = TestKotlin1.minus("我是Java调用",2);
String strpr = TestKotlin1.getA("");
System.out.println(str);
System.out.println(strpr);
}
------------打印出来的Log--------------------------
我是Java调
扩展成员变量
复制代码
val delega1 by lazy { }
by
解析public inline operator fun <T> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value
复制代码
能够看到by
其实是一个操做符,这里是Lazy
扩展getValue
方法。
lazy
原理解析@file:kotlin.jvm.JvmName("LazyKt")
//关键代码1
public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)
private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
//关键代码2
private var initializer: (() -> T)? = initializer
//关键代码3
@Volatile private var _value: Any? = UNINITIALIZED_VALUE
// final field is required to enable safe publication of constructed instance
private val lock = lock ?: this
override val value: T
get() {
val _v1 = _value
//关键代码4
if (_v1 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST")
return _v1 as T
}
//关键代码5
return synchronized(lock) {
val _v2 = _value
if (_v2 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST") (_v2 as T)
} else {
val typedValue = initializer!!()
_value = typedValue
initializer = null
typedValue
}
}
}
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
private fun writeReplace(): Any = InitializedLazyImpl(value)
}
复制代码
剖析一下
lazy
关键代码1:将
lazy(initializer: () -> T)
后面的代码块传入到SynchronizedLazyImpl(initializer)
关键代码2: 进入
SynchronizedLazyImpl
将传入的代码块赋值于initializer
关键代码3:
_value
最开始为未初始化。
关键代码4:若是
_value
不为空则直接返回(不执行咱们传入的lazy
后面代码块内的方法)
关键代码5:若是
_value
为空,作了一下同步的判断若是不为空则直接返回(不执行咱们传入的lazy
的方法),不然执行咱们的传入的代码块initializer
并拿返回值初始化_value
每次咱们调用的时候被
lazy
代理的对象的时候,其实是调用了里面的value
的get()
,当第一次调用时就会跑咱们val delega1 by lazy { 代码块}
代码块中的代码,实例完里面的SynchronizedLazyImpl#_value
后,第二次开始就是直接返回对象。保持只有一个对象实例存在。
上面的是val
属性的代理,lazy
能代理var
的属性吗?
答案:不行。里面并无实现setValue
的方法。
自定义实现代理 下面咱们举一下例子 本身来实现一个代理吧。
class Delegates{
val hello by lazy {
"HelloWorld"
}
val hello2 by X()
//由于X代理了
var hello3 by X()
}
//实现了X这个代理,并实现了 setValue getValue
class X{
private var value: String? = null
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
println("getValue: $thisRef -> ${property.name}")
return value?: ""
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String){
println("setValue, $thisRef -> ${property.name} = $value")
this.value = value
}
}
fun main(args: Array<String>) {
val delegates = Delegates()
println(delegates.hello)
println(delegates.hello2)
println(delegates.hello3)
delegates.hello3 = "value of hello3"
println(delegates.hello3)
}
-------------打印出来Log
HelloWorld
getValue: com.demo.dan.imoc_voice.Delegates@7530d0a -> hello2
getValue: com.demo.dan.imoc_voice.Delegates@7530d0a -> hello3
setValue, com.demo.dan.imoc_voice.Delegates@7530d0a -> hello3 = value of hello3
getValue: com.demo.dan.imoc_voice.Delegates@7530d0a -> hello3
value of hello3
复制代码
上面咱们实现一个代理类,并实现了
setValue
跟getValue
两个方法。这样就能够代理var
类型的成员变量。 能够看到当咱们调用的时候其实是调用了代理类的setValue
跟getValue
两个方法。
data
&&特殊写法&&解决Javabean
的问题copy、toString
,还有componentN
等方法javaBean
存在问题(可能出现没法初始化,构造方法签名不对等问题),由于javaBean
类不是final
类型可被继承,且有一个无参数构造函数。定义一个data
数据类
data class TestKotlin(val name:String,val age:Int)
复制代码
看一下转换成java
的实现
public final class TestKotlin {
@NotNull
private final String name;
private final int age;
@NotNull
public final String getName() {
return this.name;
}
public final int getAge() {
return this.age;
}
public TestKotlin(@NotNull String name, int age) {
Intrinsics.checkParameterIsNotNull(name, "name");
super();
this.name = name;
this.age = age;
}
@NotNull
public final String component1() {
return this.name;
}
public final int component2() {
return this.age;
}
@NotNull
public final TestKotlin copy(@NotNull String name, int age) {
Intrinsics.checkParameterIsNotNull(name, "name");
return new TestKotlin(name, age);
}
// $FF: synthetic method
public static TestKotlin copy$default(TestKotlin var0, String var1, int var2, int var3, Object var4) {
if ((var3 & 1) != 0) {
var1 = var0.name;
}
if ((var3 & 2) != 0) {
var2 = var0.age;
}
return var0.copy(var1, var2);
}
@NotNull
public String toString() {
return "TestKotlin(name=" + this.name + ", age=" + this.age + ")";
}
public int hashCode() {
String var10000 = this.name;
return (var10000 != null ? var10000.hashCode() : 0) * 31 + this.age;
}
public boolean equals(@Nullable Object var1) {
if (this != var1) {
if (var1 instanceof TestKotlin) {
TestKotlin var2 = (TestKotlin)var1;
if (Intrinsics.areEqual(this.name, var2.name) && this.age == var2.age) {
return true;
}
}
return false;
} else {
return true;
}
}
}
复制代码
- 能够看到
TestKotlin.java
是final
类型的,而且构造函数没有无参的。- 里面实现的
component1
,component2
实际上就是成员变量。- 默认实现了
toString
、hashCode
、equals
等方法。
咱们来调用一下 咱们写的TestKotlin
数据类
fun main() {
val t = TestKotlin("小丹", 24)
println(t.component1())
println(t.component2())
val (name,age)=t
println(name)
println(age)
}
-----------打印出来的Log
小丹
24
小丹
24
复制代码
val (name,age)=t
这种特殊写法就是data
类型的对象拥有的。咱们在迭代Array
数组的时候也有这种写法:
fun main(args:Array<String>) {
for ((index,value)in args.withIndex()){
}
}
-------------------看一下 withIndex 的实现
public fun <T> Array<out T>.withIndex(): Iterable<IndexedValue<T>> {
return IndexingIterable { iterator() }
}
---------------------看一下 返回的IndexedValue类型
public data class IndexedValue<out T>(public val index: Int, public val value: T)
复制代码
最终能够看到
IndexedValue
也是同样的data
类型。
javaBean
存在问题可使用,allOpen
跟noArg
插件,前者帮咱们去掉类前的final
后者生成无参构造函数
使用方法:
Project
)下的build.gradle
buildscript {//构件工具
ext.kotlin_version = '1.3.50'
repositories {
google()
jcenter()
mavenCentral()
}
dependencies {
......
classpath "org.jetbrains.kotlin:kotlin-noarg:${kotlin_version}"
classpath "org.jetbrains.kotlin:kotlin-allopen:${kotlin_version}"
}
}
复制代码
2.在对应的模块(module
)下的build.gradle
apply plugin:'kotlin-noarg'
apply plugin:'kotlin-allopen'
noArg{
//com.demo.dan.annotations.PoKo
//PoKo这个类是你本身建立的,要本身新建个annotations目录
// 并在下面建立一个类,而后将路径写进来
annotation("com.demo.dan.annotations.PoKo")
}
allOpen{
// 跟上面同样
annotation("com.demo.dan.annotations.PoKo")
}
复制代码
...\annotatios\PoKo.kt
annotation class PoKo
复制代码
data
类的类名上面添加注解@PoKo
data class TestKotlin(val name: String, val age: Int)
复制代码
rebuild
一下 再转换成java
代码public class TestKotlin {
................省略其余的代码
public TestKotlin() {
}
}
复制代码
能够看到这里已经帮咱们生成了无参构造函数跟去掉final
修饰关键字。
注意:由于注解是在编译期的时候生效的,也就是说咱们在写代码的时候仍是调用不了无参构造函数,可是能够经过反射获取到无参构造函数。
kotlin
默认是静态内部类,非静态内部类须要使用inner
关键字//静态内部类
class TestKotlin {
class Inner{
}
}
//非静态内部类
class TestKotlin1{
inner class Inner1{ }
}
fun main() {
val inner = TestKotlin.Inner()
val inner1 = TestKotlin1().Inner1()
}
复制代码
当内部类须要外部类的状态时,则可使用非静态内部类,由于非静态内部类默认持有外部类的引用。若是不须要持有外部类的引用,则使用静态内部类。
@Outter
的使用,当非静态内部类跟外部类有成员名字相同时,获取外部类的成员能够用this@外部类名.成员变量
class TestKotlin1 {
val a = "TestKotlin1-string"
inner class Inner1 {
val a = "Inner1-string"
fun aInnerfun(): String {
return a
}
fun aTestKotlinfun(): String {
return this@TestKotlin1.a
}
}
}
复制代码
object
)的使用------------------kotlin的写法
val view =View(context)
view.onClickListener = object : View.OnClickListener{
override fun onClick(v: View?) {
}
}
----------------java的写法
View view = null;
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
复制代码
不一样于java ,Ktolin
的object:
还支持同时实现单继承多实现
interface TestInterface{
fun test()
}
view.onClickListener = object: TestInterface,View.OnClickListener {
override fun test() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onClick(v: View?) {
}
}
复制代码
enum class LogLevel{
VERBOSE,DEBUG,INFO,WARN,ERROR
}
---相似于下面的kotlin代码
class LogLevel2 protected constructor{
companion object{
val VERBOSE = LogLevel2()
val DEBUG= LogLevel2()
val INFO= LogLevel2()
val WARN= LogLevel2()
val ERROR= LogLevel2()
}
}
复制代码
kotlin
的enum
中要定义方法,记得要用;
将成员跟方法隔开enum class LogLevel(val id:Int){
VERBOSE(0),DEBUG(1),INFO(2),WARN(3),ERROR(4) ;
fun getTag():String{
return "$id,$name"
}
}
复制代码
sealed class
子类有限(可数)的类:子类只能在同一个文件中存在,因此其余的文件继承不了它,因此子类有限(可数)。
sealed class PlayerCmd {
class Play(val url: String, val position: Long = 0): PlayerCmd()
class Seek(val position: Long): PlayerCmd()
object Pause: PlayerCmd()
object Resume: PlayerCmd()
object Stop: PlayerCmd()
}
复制代码