常量/变量延迟初始化
1、使用lazy委托延迟常量初始化:
val <名称>: <类型> by lazy{<Lambda表达式>}
2、使用lateinit关键字延迟非空变量初始化(不能修饰基本类型):
lateinit var <名称>: <类型>
lateinit关键字只是让编译器忽略此变量的初始化检查,如果调用时未完成初始化,将会抛出UninitializedPropertyAccessException异常。如果使用前无法无确定对应变量是否已完成初始化,可以使用isInitialized进行判断:
private lateinit var name:String
fun checkInit():Boolean= this::name.isInitialized
3、自定义委托实现。
声明静态常量/变量
Kotlin中没有static关键字,声明静态常量/变量需要使用顶级属性和伴生属性来完成,以声明静态常量举例,有三种写法:
1)顶级作用域内使用const val修饰;
2)在class伴生对象中使用const val修饰;
3)在class伴生对象中使用val修饰,并添加@JvmStatic注解;
const val name1: String = "name1"
class Demo {
companion object {
const val name2: String = "name2"
@JvmStatic
val name3 = "name3"
}
}
在顶级作用域中声明的属性为文件所有,class伴生对象中声明的属性为class所有,三者时使用时略有差别:
//在Kotlin文件中使用
import com.demo.kotlin.Demo
import com.demo.kotlin.name1
class KTest {
val n1 = name1
val n2 = Demo.name2
val n3 = Demo.name3
}
//在Java文件中使用
import com.demo.kotlin.Demo;
import com.demo.kotlin.DemoKt;
public class JTest {
String n1 = DemoKt.name1;
String n2 = Demo.name2;
String n3 = Demo.Companion.getName3();
}
Kotlin声明静态变量,与声明常量基本相同,只需要去掉cosnt,再将val改为var即可。
创建单例
Kotlin中没有static关键字,需要利用object、companion、lazy关键字实现(也可以使用注解@JvmStatic在编译后生成对应的Java静态方法)。
object关键字主要有三种使用场景
- 对象声明(object declaration):
object class <类名>…,声明一个类并创建此类的静态常量。 - 伴生对象(companion object):
class <类名>{companion object {…}},声明一个名为Companion的内部类,并在创建一个名为Companion的Companion类的静态常量。 - 对象表达式(object expression):
object <属性名>:<类名/接口名><构造参数(非必要)>{…},声明一个匿名内部类实例。
1、利用伴生(companion)声明单例(饿汉模式):
class Single {
val name = "Single"
companion object {
val mInstance = Single()
}
}
……
System.out.println(SingleA.mInstance.name)
2、利用具名对象(object)声明单例(饿汉模式):
object Single {
val name = "Single"
}
……
System.out.println(Single.name)
3、使用委托(lazy)声明单例(双重检验模式):
class Single {
val name = "Single"
}
val mInstance: Single by lazy {
Single()
}
……
System.out.println(mInstance)
Jave调用Kotlin代码
Kotlin可以直接调用Java代码,但是Java调用Kotlin代码时几种场景需要注意:
1、Java调用Kotlin内的object class、companion内属性或方法:
//定义Kotlin伴生
class KotlinTest {
companion object {
val message: String = "call kotlin code"
fun print(message: String) {
System.out.println(message)
}
}
}
//从Java文件调用Kotlin代码
public void callKotlin() {
KotlinTest.Companion.print(KotlinTest.Companion.getMessage());
}
-------------------------------------------------------------------
//定义Kotlin静态对象
object KotlinTest {
val message: String = "call kotlin code"
fun print(message: String) {
System.out.println(message)
}
}
//从Java文件调用Kotlin代码
public void callKotlin() {
KotlinTest.INSTANCE.print(KotlinTest.INSTANCE.getMessage());
}
2、Java调用Kotlin内的扩展方法:
Kotlin中调用扩展方法直接使用<对象>.<方法>(<其他参数>)执行,其编译后为Java中的静态方法,从Java文件调用Kotlin中定义的扩展方法,<文件名>.<方法>(<对象>,<其他参数>),实际就是调用编译生成的对应静态方法:
//Kotlin定义扩展方法
fun String.ellipsize(length: Int): String {
return if (this.length <= length) {
this
} else {
this.substring(0, length - 1) + "…"
}
}
//Java中调用
TestKt.ellipsize("abcdefg", 5);
常用注解
Transient:替代transient关键字;@Volatile:替代volatile关键字;@Synchronized:只能用于函数上(包括Koltin中属性对应的set和get方法),同synchronized关键字;声明同步代码块时,需要使用Kotlin中提供的内联函数:
public inline fun <R> synchronized(lock: Any, block: () -> R): R
@JvmOverloads:作用于普通函数和构造函数,根据方法中的默认参数个数,依次从右向左去除含有默认值的参数,生成对应的重载方法。@JvmStatic:作用于函数和Kotlin属性(字段加上其set和get和方法),编译后生成静态方法或静态变量。@JvmField:作用于字段,使得编译器不再对该字段生成getter/setter并将其作为公开字段。@JvmSynthetic:作用于字段(需要先使用@JvmField声明)或方法,编译后无法在Java环境中调用。@JvmName:作用于文件和函数,修改编译后的名称,外部需要使用修改后的名称调用。@file:标明作用范围为当前文件,必须写在文件最顶端。
@file:Suppress("SetTextI18n")//忽略文件内所有“SetTextI18n”警告
@file:JvmName(name = "newName")//修改当前文件名为“newName”
package xxxxxxx
impoert xxxxxxx
……
@JvmMultifileClass:作用于文件,将文件内编译的内容合并到同一个类文件内。
//文件Tst1.kt
@file:JvmName("TstKt")
@file:JvmMultifileClass
fun func1(){……}
//文件Tst2.kt
@file:JvmName("TstKt")
@file:JvmMultifileClass
fun func2(){……}
//如果没加上JvmMultifileClass注解将会编译报错,注解后会Tst.kt内将包含func1和func2。