kotlin 语法
1.变量定义
val 定义常量 相当于 final
var 定义变量 非final类型变量
//常量
val x: Int = 10 //要给默认值
val x1 = 10 //推断,等同与上边
//变量
var y:Int = 10
var y1 = "hello world"
companion object {
//public final static I staticVal = 10
const val staticVal = 10
//private final static I zxy
val staticVal2 = 100
}
2.逻辑控制
if(num1>num2) num1 else num2
//类似 Java switch
when(var){
0 -> {}
1 -> {}
else -> {}
}
//还可以这样写
when(var){
is Int -> {}
is Float -> {}
else -> {}
}
//或者这样写,比Java要灵活
fun test(name: String) = when {
y1.startsWith("hi") -> {}
y1.endsWith("world") -> {}
y1 == "niHao" -> {}
else -> {}
}
常用的循环
for (i in 0..10){}
for (i in list){}
for (i in 0..list.size)
for (i in 0 until 100 step 2){}
for (i in 10 downTo 1) //倒序
for ((index, entry) in list.withIndex())
list.forEach { }
for ((key, value) in map)
其他一些有用的内置函数 list.map{} list.maxBy{} list.filter{}
3.集合
实例化:
val list = ArrayList() //类似Java 写法
val list = listOf(0,1,2,3)//不可变,不可add remove
val list = mutableListOf<Int>() //可变
//同样的还有
val map = mapOf(1 to 1, 2 to 2,3 to "3")
val map = mutableMapOf<Int,Int>()
val array = arrayOf(0, 1, 2)//长度不可变,值可变
val array = arrayListOf<Int>()
val array = IntArray(3)
//多维数组
val array2d = Array(3,{Array(3){it -> 0}})
4.类:继承/构造函数
- Kotlin中类与Java类没什么太大差别
class HelloWorld{}
- Kotlin 中继承省去extends、implements 关键字
class Student: Person(), Interface{}
但是一个类必须加上open才可以被继承 - Kotlin 中主构造函数
主构造函数:
1.默认不带参数的构造函数,也可以显式给添加参数;
2.特点就是没有函数体, 可在init{}做初始化操作;
3.在类名的后边;
4.要调用父类的构造函数;
class Student: Person(){
init{
//do something
}
}
- Kotlin 中次构造函数
1.constructor()
2.有函数体
3.必须调用主构造(或者间接调用)
class Other() : Fat() {
constructor(x:Int): this(){}
}
//间接调用
class Other() : Fat() {
constructor(x:Int): this(){}
constructor(x:Int, y:String): this(x){}
}
类可以没有主构造函数但是需调用父构造函数
class Other :Fat{
constructor():super(){}
}
自定义View可以这么写,避免重写多个构造
class CustomView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
}
5.运算符
运算符 | Java | Kotlin |
---|---|---|
与 | & | and |
或 | | | or |
非 | ~ | inv |
抑或 | ^ | xor |
左移 | << | shl |
右移 | >> | shr |
其他 | equals() | == |
其他 | == | === |
6.可见性修饰符
修饰符 | Java | Kotlin |
---|---|---|
public | 所有类可见 | 所有类可见(默认) |
private | 当前类可见 | 当前类可见 |
protected | 当前类、子类、同包可见 | 当前类、子类 |
default | 同包内可见(默认) | 无 |
internal | 无 | 同意模块类可见 |
7.数据类/单例类/密封类
- 数据类
data class HelloWorld(var v1 = 1,val v2: Int)//默认参数
比Java 省去了 equals()/hashCode()/toString() 。
- 单例类
object HelloWorld{}
该类内部方法可通过类名.方法名
调用,但类内部的方法并非是静态方法,如果要定义静态方法需要定义注解或是定义成顶层方法。 - 密封类
主要配合when() 使用 ,优化else分支。
sealed class Action
class Cry: Action()
class Run:Action()
class Eat:Action()
fun doSomething(action:Action) = when(action) {
is Cry -> {}
is Run -> {}
is Eat -> {}
}
8.标准函数
Kotlin 提供了一些标准函数在Standard.kt 文件中定义
- with
用法 with(var1){} ,返回最后一行 (block()函数)
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return receiver.block()
}
- apply list.apply{},返回调用者本身
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}
- let x.let{} , 返回最后一行
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
- 其他的可以查看函数一下该文件(also、run等)
9.扩展函数
可以直接给已定义的类(比如系统类)添加函数;
fun String.getNumberCount():Int{
var num = 0
for(c in this){
if(c is Char) num++
}
return num
}
//可以直接调用
val num = "iuqwe189123hqwwqe".getNumberCount()
10.运算符重载
在Java 中经常见到字符串相加
String h = "hello" + "world";
但是在kotlin中,对象也可以相加
class Student(val score:Int){
operator fun plus(that: Student): Student{
return Student(this.score + that.score)
}
}
//使用
val s1 = Student(70)
val s2 = Student(80)
val s3 = s1 + s2
类似的方法还有
minus(-) 、 times(*)、div(/)、rem(%) 其他
可在Primitives.kt 查看
11.高阶函数
语法:函数内接收一个函数类型参数
fun example(func: (String, Int) -> Unit){
}
因此可以自定义一些高级功能:
fun StringBuilder.build(block: StringBuilder.() -> Unit):StringBuilder {
block()
return this
}
其实就是类似标准函数中apply 写法
然后就可以这么用
val sb = StringBulider().build{
append("hello")
append("\u2000")
append("world")
}
内联函数
上边函数其实是在build函数中创建了匿名内部类,每次调用都会创建一个Function匿名内部类来替换内部的block 方法。为了消除性能开销kotlin 提供了inline
关键字。
inline fun StringBuilder.build(block: StringBuilder.() -> Unit):StringBuilder {
block()
return this
}
这个关键字的作用就是,直接将block的方法体替换到build方法内部,代码解释就是:
inline fun test(num1:Int, num2: Int, block: (Int, Int)): Int{
return
}
//调用
val x = test(10, 20){
10 + 20
}
//加上inline 相当于
fun test(num1:Int, num2: Int): Int{
return num1 + num2// block()
}
还有一点就是inline 修饰的高阶函数,block 函数内部可以直接return ,并且会直接结束掉该方法,而非内联函数则只能局部返回,代码可能比较直观:
fun printString(bool: Boolean,block: (Boolean)-> Unit){
println("start")
block(bool)
println("end")
}
//调用
println("main start")
printString(true){
println("block start")
if (it) return@printString
println("block end")
}
println("main end")
//打印
I/System.out: main start
I/System.out: block start
I/System.out: main end
//加上inline
inline fun printString(bool: Boolean,block: (Boolean)-> Unit){
println("start")
block(bool)
println("end")
}
//调用
println("main start")
printString(true){
println("block start")
if (it) return
println("block end")
}
println("main end")
//打印
I/System.out: main start
I/System.out: block start
与inline
相关的还有 noinline 、 crossinline
noinline 与inline 顾名思义就是对立的关系,那oninline 又有什么意义呢?往下看,使用方法:
inline fun printString(block1:()->Unit, noinline block2:() ->Unit){
block1()
block2()
}
noinline 其实是结合inline 使用的,当参数有多个函数类型参数时,想要指定某个参数不内联就在其参数前加上noinline
关键字,但是还是没有搞懂存在的意义,noinline 作用其实是就是可以把非内联函数类型参数传递给任何其他函数,而内联函数则只能传递给另外一个内联函数,不过平时用的可能不太多。
而crossinline
又是什么含义?
12.泛型
1.基本用法和Java差不多
class Hello<T>{
fun method(par: T){
}
}
class Hello{
fun <T> method(param: T){
}
}
//指定上界, 只能传数字类型
class Hello{
fun <T: Number> method(param: T){
}
}
默认kotlin 泛型都是可空的因为,默认的上界是Any?,
如果想改成非空的,可以指定上界为Any 或想要的类型。
2.泛型实例化
意思就是可以将一个泛型参数实例化,就可以直接调用其方法,这是Java 所不具备的;
必要条件 inline
修饰的方法且 reified
在泛型前。
定义代码如下:
inline fun <reified T> getType()=T::class.java
有什么作用呢?
看下边代码:
val intent = Intent(context, OtherActivity::class.java)
intent.putExtra("key", "value")
startActivity(intent)
//这是常规写法,这是用泛型实例化优化后
inline fun <reified T> startActivity(context: Context, block: Intent.() -> Unit){
val intent = Intent(this, T::class.java)
intent.block()
context.startActivity(intent)
}
//使用
startActivity<MainActivity>(this){
putExtra("key", "value")
}
定义成工具方法可见,代码简洁了不少。
3.协变和逆变
协变out,泛型只允许出现在返回值
class Hello<out T>{
fun method(): T{
}
}
逆变in,泛型只允许出现在参数中
class Hello<in T>{
fun method(param: T){
}
}
13.语法糖infix
1.不能定义成顶层函数;
2.有且只能有一个参数;
infix fun String.add(str: String):Boolean{
return str.length> temp.length
}
"hello" add "world"
14.委托
1.类委托
含义就是将实现交给另外一个类来实现;
定义一个自己的List 类
class MyList<T>(val list:List<T>) : List<T>{
override fun add(t: T) = list.add(t)
override fun remove(t: T) = list.remove(t)
//... 省略其他方法
}
这个类有什么意义?
其实在这个类中可以加入自己定义的方法,其他的方法又委托类来实现,但是这在Java 中可能是很搞笑的做法,因为List 接口所有方法都要手动调用;
但是Kotlin 提供了by 关键字,所以上边代码可以改为
class MyList<T>(val list:List<T>) : List<T> by list{
override fun contains(t: T) = false
fun testMethod1(){}
fun testMethod2(){}
fun testMethod3(){}
fun testMethod4(){}
}
2.属性委托
委托属性的思想就是把一个属性交给另外一个类来完成。
如何理解:
class Hello{
val p by Delegate()
}
class Delegate {
private var _value: Any? = null
operator fun getValue(other: Other, property: KProperty<*>): Any? {
return _value
}
operator fun setValue(other: Other, property: KProperty<*>, any: Any?) {
_value = any
}
}
此时p 的set get 就交给Delegate#setValue Delegate#getValue 方法来实现
具体又是如何应用呢?最常见就是val p by lazy{}
可以通过前边代码来懒加载p属性, lazy 是kotlin的一个高阶函数:
public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)
lazy 会创建一个SynchronizedLazyImpl 对象,当调用get时,是执行了SynchronizedLazyImpl#getValue ,getValue接收一个Lambda表达式,返回该表达式最后一行代码。
private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
private var initializer: (() -> T)? = initializer
@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
if (_v1 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST")
return _v1 as T
}
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)
}
有兴趣或是有需要的话,可以参照实现自己的委托类。
网友评论