文章目录
访问修饰符open
kotlin中默认类和方法是final,如果允许创建一个类的子类,需要使用open修饰符来表示这个类,另外需要给每一个可以被重写的属性或者方法添加open修饰符
open class OkhttpClienet internal constructor(builder:Builder):Cloneable,Call.Factory,WebSocket.Factory{
}
for循环
//顺序 遍历[0,100]
for(index in 0..100){
}
//倒序 遍历[0,100]
for(index in 100 downTo 0){
}
//顺序 遍历[0,100)
for(index in 100 downTo 0){
}
// 遍历 [0,100] 设置步长n
for(index in 0..100 step 5 ){
}
val list_test = listOf(User("张三", 25), User("李四", 26), User("王五", 27))
//取出集合中每个元素
for(user in list_test){
Log.d(TAG, "$user")
}
// 取出下标
for(index in list_test.indices){
}
//取出下标和值
for( (index,value) in list_test.withIndex){
}
对象
-
对象表达式
相对于匿名内部类
java匿名内部类的局限性: 如果在匿名内部类中添加一些属性和方法。那么在外界是无法调用的。
语法形式: object[:接口1,接口2,类型1,类型2…]{}
只需要"一个对象而已" 并不需特殊的类型,不实现任何接口和类,并且在匿名内部类中添加方法
fun foo() {
val adHoc = object {
var x: Int = 0
var y: Int = 0
fun a() {
println("a invoked")
}
}
adHoc.a()
print(adHoc.x + adHoc.y)
}
实现一个接口或类
interface AA {
fun a()
}
fun main(args: Array<String>) {
val aa = object : AA {
override fun a() {
println("a invoked")
}
}
aa.a()
}
实现多个接口和类
fun main(args: Array<String>) {
val cc = object : AA, BB() {
override fun a() {
}
override fun b() {
}
}
cc.a()
cc.b()
}
匿名对象只有定义成局部变量和private成员变量时,才能体现它的真实类型。如果你是将匿名对象作为public函数的返回值或者是public属性时,你只能将它看做是它的父类,当然你不指定任何类型时就当做Any看待。这时,你在匿名对象中添加的属性和方法是不能够被访问的。
-
对象声明
在object关键字后跟一个名称。对象声明的初始化过程是线程安全的,即实现了单例模式;
一个匿名内部类肯定是实现了一个接口或者是一个继承类,并且只能是一个。需要引用该对象,我们直接使用其名称即可。
object修饰的类为静态类,里面的方法和变量都是静态的。
对象声明不能在局部作用域(嵌套在函数内部)object定以后即刻实例化,不能有定义构造函数,定义在内部的object并不能访问类的成员
object DataProviderManager {
fun registerDataProvider(provider: DataProvider) {
// ……
}
val allDataProviders: Collection<DataProvider>
get() = // ……
}
<!--引用-->
DataProviderManager.registerDataProvider(...)
companion object 定义属于类的本身,只在类里面能定义一次。可以有名字也可以省略。可以实现多个接口。扩展类的静态成员。(内部类)
interface Factory<T> {
fun create(): T
}
class MyClass {
companion object : Factory<MyClass> {
override fun create(): MyClass = MyClass()
}
}
val f: Factory<MyClass> = MyClass
对象表达式和对象声明之间的语义差异
- 对象表达式是在使用他们的地方立即执行(及初始化)的;
- 对象声明是在第一次被访问到时延迟初始化的;
- 伴生对象的初始化是在相应的类被加载(解析)时,与 Java 静态初始化器的语义相匹配。
静态变量和静态方法
kotlin实现是将变量和方法包含在companion object 域中即可。const val 对应final static 修饰。
java中想直接通过类名.静态变量或者类名.静态方法方式调用。 则在kotlin中加上 @JvmField修饰静态变量,@JvmStatic修饰静态方法。
lateinit
- lateinit 修饰可变的属性, 必须是var修饰。
- lateinit 不可以修饰基本类型属性
- lateinit 修饰的属性必须进行赋值后才可使用
原因是kotlin 会对lateinit修饰的属性进行null的初始,基本类型没有null。
属性修改为自定义的代码而不修改原有代码
public class Person{
var name: String = ""
get() = field.toUppercase()
set(value) {
field = "name: $value"
}
}
扩展函数
有个优点 就是在调用方法的时候,不需要把整个对象当做参数传入。
<!--这个函数不需要传入Content, 可以被任何Content和其子类调用-->
fun Context.toast(message: String, duration: Int = Toast.LENGTH_SHORT){
Toast.makeText(this,String,duration)
}
let函数
public inline fun<T,R> T.let(block: (T) -> R): R{
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
let扩展函数实际上是个作用域,返回值为函数块的最后一行或指定return表达式。
适用场景:
- let函数处理需要针对一个可null对象的统一处理。
- 需要明确一个变量所处特定的作用域范围内可以使用。
override fun onCreate(saveInstanceState: Bundle?){
super.oncreate(savedInstanceState)
arguments?.let{
param1 = it.getString(xxxx)
....
}
}
also函数
public inline fun<T> T.also(block: (T) -> Unit): T{
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block(this)
return this
}
- also 函数和let函数相比, 返回值不同,其他类类似的。
let 函数的返回值可以是 Lambda 表达式 的返回值,而 also 函数的返回值是调用 also 函数的对象。 also函数适合链式操作
with函数
@kotlin.internal.InlineOnly
public inline fun <T,R> with(receiver: T, block:T.() ->R): R{
contract{
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return receiver.block()
}
with函数接收一个对象T 和y一个作为扩展函数的函数。方法是要让T去执行body扩展函数。
按着lambda表达式,最后一个参数是函数,可以放到括号外的约定。所有第二个函数可以放到圆括号外。
第二个参数的代码块里,可以使用this和直接访问public的方法和属性。
with函数的返回值,是代码块中表达式的最后一个值。
使用场景:with函数用于对同一个对象包含多次操作而不需要反复把对象的名称写出来。
with(tv_text){
text = "xxxxx"
textSize = xxx
...
}
run函数
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
run函数返回值为lambda函数的最后一行的值或者指定的return的表达式。
使用场景
适用于let,with函数任何场景。因为run函数是let,with两个函数结合体,准确来说它弥补了let函数在函数体内必须使用it参数替代对象,在run函数中可以像with函数一样可以省略,直接访问实例的公有属性和方法,另一方面它弥补了with函数传入对象判空问题,在run函数中可以像let函数一样做判空处理
apply函数
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T{
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
retrun this;
}
apply函数返回传入对象的本身,一般用于一个对象实例初始化的时候,需要对对象中的属性进行赋值。
Buidler模式中,对属性赋值特别适用。
fun dispatcher(dispatcher: Dispatcher) = apply{
this.dispatcher = dispatcher
}
对于with,T.run,T.apply接收者是this,而T.let和T.also接受者是it;对于with,T.run,T.let返回值是作用域的最后一个对象(this),而T.apply和T.also返回值是调用者本身(itself)。
kotlin JVM 常用注解参数解析
@file:kotlin.jvm.JvmMultifileClass
@file:kotlin.jvm.JvmName("StandardKt")
package kotlin
文件名的注解定义必须在package前。
-
@file:kotlin.jvm.JvmName(“StandardKt”): 代表可以使用定义name直接调用方法了。
-
@file:JvmMultifileClass:
如果有多个 Kt 文件都进行自定义 Name ,并且有重复的,加上 @file:JvmMultifileClass,这样的结果就是编译后会强制性的把多个文件内容合并在一起。
协程
协程相当轻量级的线程,一个线程中可以执行多个协程。 Coroutine协程是基本可以替代RxJava.
在代码成面将异步任务协程同步的调用形式。