java被 Oracle收购后,谷歌经常被Oracle告侵权,所以谷歌选择了Kotlin作为Android开发的第一语言,在Android官网上 说Kotlin是免费且开放的,是由一家特别厉害的公司JetBrains开发的静态编程语言,AndroidStudio也是根据他家的IDEA改的,谷歌也贡献了开源代码 Kotlin的优点:
Kotlin 的现代语言功能让您可以专注于表达自己的想法,少编写样板代码。
借助自身类型系统所含的 @Nullable 和 @NonNull,Kotlin 可帮助您避免 NullPointerExceptions。使用 Kotlin 的 Android 应用发生崩溃的可能性降低了 20%。
可以和Java代码互通,互相调用
Kotlin 协程可简化异步编程,让您能够轻松高效地执行网络调用和数据库更新等常见任务。
类型推导 根据初始化的类型进行类型推导 可变变量定义 var
不可变变量定义val 相当于java的final修饰 Kotlin是一个静态语言 ,编译期就决定的东西
class VariableDemo { // var <标识符> : <类型> = <初始化值> // val <标识符> : <类型> = <初始化值> // var userName:String="爱码士" var name="爱码士"//自动推导为字符串 val age=100//自动推导为 Int } 复制代码
decompiledJava(用插件先把Kotlin转为字节码,再反编译成java文件)后的代码
public final class VariableDemo { @NotNull private String name = "爱码士"; private final int age = 100; @NotNull public final String getName() { return this.name; } public final void setName(@NotNull String var1) { Intrinsics.checkParameterIsNotNull(var1, "<set-?>"); this.name = var1; } public final int getAge() { return this.age; } } 复制代码
由以上代码可以看出var转为java之后是有get和set方法的,而val用了final修饰之后并且没有set方法,说明了用var修饰的变量可读可写,用val修饰的变量可读不可写
不带返回值的方法void==Unit 可以省略
fun testFun(number1:Int,number2:Int):Unit{ println(number1+number2) } 复制代码
有返回值返回值 和参数的方法
fun testFun(number1:Int,number2:Int):Int{ println(number1+number2) return number1+number2 } 复制代码
一种更高级的写法 方法 = 推导返回值类型
fun add(number1: Int,number2: Int) = number1+number2 //返回值推导成Int fun add3(number1: Int, number2: Int) = "爱码士"//返回值推导成String 复制代码
java里可以有可变参数,Kotlin里也有需要用vararg 关键字来修饰 可变参数(可边长的参数)
fun lenMethod(vararg number:Int){ println(number.size) } 复制代码
lambda表达式函数(这里先举个例子,以后专门写个文章来学习lambda)
fun main(){ // lambda表达式函数 val addMethod : (Int, Int) -> Int = {number1, number2 -> number1 + number2} val r= addMethod(9, 9) println(r) } 复制代码
写起来会快一点
val name = "爱码士" val age = 28 val sex = 'M' val info = "ABCDEFG" println("name:$name, age:$age, sex:$sex info:$info") 复制代码
三个双引号,原样输出,换行不需要转义字符,
val infoMesage = """ AAAAAAAAAAA"aaa" BBBBBBBBBBB CCCCCCCCCCC DDDDDDDDDDD EEEEEEEEEEE """ // 前置空格 println(infoMesage)//输出来会有前置空格 val infoMesage2 = """ AAAAAAAAAAA BBBBBBBBBBB CCCCCCCCCCC DDDDDDDDDDD EEEEEEEEEEE """.trimIndent() // 没空格 复制代码
trimIndent()去掉前置空格,具体什么效果大家可以敲一敲 去试试 显示999.99999.99999.99{‘$’}999
val price = """ ${'$'}99999.99 """.trimIndent() println(price) 复制代码
var name:String?=null//?会发一个通知,告诉所有调用者,现在这个变量是可以为null的,你们调用者自己去实施补救措施 fun main() { //name.length//如果不补救则会编译报错,报下图的错 } 复制代码
一共三种补救措施 第一种就是方法内允许返回空值,在返回值返回的后边加一个?,这样的话就将补救措施交给了返回值的调用者
fun main() { var testStr=test() //testStr.length } fun test():String?{ return null } 复制代码
这种写法testStr.length报的错误和上面一样的,如果把test方法返回值的?去掉,则这个方法是不允许返回null的,testStr.length是不会报错的 第二种补救措施 调用的这个属性的时候,点前边加一个?,表示如果这个属性为null,则后边的代码不执行
fun main() { var testStr=test() testStr?.length//如果testStr为null,则.length不执行 } fun test():String?{ return null } 复制代码
第三种补救措施在调用的时候,点前面加两个!!,表示这个属性一定不为null,后面的一定执行
fun main() { var testStr=test() testStr!!.length//如果testStr为null,则.length不执行 } fun test():String?{ return null } 复制代码
第三种补救措施一定要慎用,在确定这个属性为百分之百不为null的情况下可以这样用,否则会出现空指针异常的情况
fun sectionTest(){ //区间 .. 只能从小数到大数 for (index in 1..10){ print(index) } println("") //区间 down to 只能从大数到小数 for (index in 10 downTo 1){ print(index) } println("") //step 步幅 for (index in 1..10 step 4){ print(index) } //in 和 downTo是闭区间 unitl 半闭半开区间 //半闭半开区间 也是只能从小数到大数 for(index in 1 until 10){ print(index) } } 复制代码
输出结果:
==比较值本身相当于,equals也能用,但是有黄色波浪线 ===比较对象地址
val name1: String = "爱码士" val name2: String = "爱码士" // --- 比较值本身 // == 等价 Java的equals println(name1.equals(name2)) println(name1 == name2) // --- 比较对象地址 val test1:Int? = 10000 val test2:Int? = 10000 println(test1 === test2) // false 复制代码
数组 arrayOf泛型 类型推导
val numbers = arrayOf(1, 2, 3, 4, 5, 6, 7, 8) //取值numbers[index] numbers[0] //方式二 val numbers2 = Array<String>(10, {value: Int -> ("aaa") }) // val numbers2 = Array<String> (10,//数组大小 {value: Int //数组下标- > ("aaa")//给下标为value的赋值aaa }) 复制代码
也可以这样写
val numbers2 = Array<String>(10, {value: Int -> if(value==5) ("666") else ("aaa") }) for (value in numbers2) { println(value) } 复制代码
decompiledJava后的代码
public static final void main() { byte var1 = 10; String[] var2 = new String[var1]; boolean var5; for(int var3 = 0; var3 < var1; ++var3) { var5 = false; String var8 = var3 == 5 ? "666" : "aaa"; var2[var3] = var8; } String[] var11 = var2; int var4 = var2.length; for(int var10 = 0; var10 < var4; ++var10) { String value = var11[var10]; var5 = false; System.out.println(value); } } 复制代码
表达式比大小
val age=5; val age1=10; val maxValue=if (age>age1) age else age1 复制代码
区间判断
val age=5; if(age in 1..18){ println("未成年") }else{ println("已成年") } 复制代码
switch的升级版when
val age=5; when(age){ in 1..18->{//判断是否在1到18之间 } 19,21,22,24->{//满足其中一个就执行这个分支 } else->{//不满足以上条件 走这个分支 } } 复制代码
when的类型推导
var str= when(age){ in 1..18->{ "年龄为$age,未成年" } 19,21,22,24->{ "年龄为$age,成年了" } else->{ "年龄为$age,其他" } } println(str) 复制代码
如果各个分支的返回类型不相同,str则会被推导成Any类型,相当于Java当中的Object
在 Kotlin 中任何表达式都可以用标签来标记。 标签的格式为标识符+ @ 符号,例如:aaa@、bottom@都是有效的标签, 要为一个表达式加标签,我们只要在其前加标签即可。 标签的应用 break
tttt@ for (i in 1..20) { for (j in 1..20) { println("i:$i, j:$j") if (i == 5) { // break // j循环 给break break@tttt // i循环 给break } } 复制代码
return
fun testLabel(){ var numbers= arrayOf(1,2,3,4,5,6) testFor@numbers.forEach { when(it){ 5->{ // return //不打印aaa return@forEach//打印aaa } } } println("aaa") } 复制代码
this
class SafeDemo { val name="爱码士" inner class SafeDemoInner{ val name="inner 爱码士" fun test(){ println(this.name)//inner 爱码士 println(this@SafeDemo.name)//"爱码士" } } } 复制代码
for循环
var items = listOf<String>("李四", "张三", "王五") for (item in items) { println(item) } items.forEach { println(it) } for (index in items.indices) { println("下标:$index, 对应的值:${items[index]}") } 复制代码
先来一个空类
//默认public 所以不用写public class Test { } 复制代码
class Test(val age:Int) {//主构造的写法 constructor():this(5)//次构造 次构造 必须调用主构造 constructor(name:String):this(5)//次构造 } //使用的时候不需要new关键字 fun main() { Test(0) } 复制代码
上面这种写法,转成java之后class 是用final修饰的,所以不能被继承,但是我想写一个父类怎么办呢,class前面用open修饰,这个类就可以被继承了,就去掉了final关键字
open class Test(val age:Int) {//主构造的写法 constructor():this(5)//次构造 次构造 必须调用主构造 constructor(name:String):this(5)//次构造 } 复制代码
在Java中所有的属性值是可以有默认值的,默认为null,是没有什么问题的,但是Kotlini中,如果不给属性赋值,就会报错 解决办法
val number=0; var id:String ?= null lateinit var url:String//懒加载的时候用的时候一定要初始化,否则会空指针异常 复制代码
抽象类 和接口 和java的写法相似
interface ICallBack { fun onCallBack() } abstract class TestAbstract { abstract fun initView() } //继承和实现接口都使用:然后用逗号隔开,继承抽象类或者 open修饰的类的时候,要声明主构造 class TestInterface: TestAbstract(),ICallBack{ override fun initView() { // TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } override fun onCallBack() { // TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } } 复制代码
JavaBean的写法,Kotlin中用dataclass代替了JavaBean,还生成了copy函数
data class UserBean(val userName:String,val password:String) fun main() { var user=UserBean("aaa","bbbb") var (username,password)=user.copy() var (_,amszlk)=user.copy()//只想copypassword println("username:$username,password:$password") println(amszlk) } 复制代码
转成java的代码
public final class UserBean { @NotNull private final String userName; @NotNull private final String password; @NotNull public final String getUserName() { return this.userName; } @NotNull public final String getPassword() { return this.password; } public UserBean(@NotNull String userName, @NotNull String password) { Intrinsics.checkParameterIsNotNull(userName, "userName"); Intrinsics.checkParameterIsNotNull(password, "password"); super(); this.userName = userName; this.password = password; } @NotNull public final String component1() { return this.userName; } @NotNull public final String component2() { return this.password; } @NotNull public final UserBean copy(@NotNull String userName, @NotNull String password) { Intrinsics.checkParameterIsNotNull(userName, "userName"); Intrinsics.checkParameterIsNotNull(password, "password"); return new UserBean(userName, password); } // $FF: synthetic method public static UserBean copy$default(UserBean var0, String var1, String var2, int var3, Object var4) { if ((var3 & 1) != 0) { var1 = var0.userName; } if ((var3 & 2) != 0) { var2 = var0.password; } return var0.copy(var1, var2); } @NotNull public String toString() { return "UserBean(userName=" + this.userName + ", password=" + this.password + ")"; } public int hashCode() { String var10000 = this.userName; int var1 = (var10000 != null ? var10000.hashCode() : 0) * 31; String var10001 = this.password; return var1 + (var10001 != null ? var10001.hashCode() : 0); } public boolean equals(@Nullable Object var1) { if (this != var1) { if (var1 instanceof UserBean) { UserBean var2 = (UserBean)var1; if (Intrinsics.areEqual(this.userName, var2.userName) && Intrinsics.areEqual(this.password, var2.password)) { return true; } } return false; } else { return true; } } } 复制代码
Kotlin的単例模式Object类
object ObjectTest { fun showToast(){ } } //调用 fun main() { ObjectTest.showToast() } 复制代码
转成Java之后的代码
public final class ObjectTest { public static final ObjectTest INSTANCE; public final void showToast() { } private ObjectTest() { } static { ObjectTest var0 = new ObjectTest(); INSTANCE = var0; } } 复制代码
伴生对象companionobject,为了方便理解咱们先上代码
class CompanionObjectTest { companion object{ val name="爱码士" fun show(){ name.length } } } //调用 fun main() { CompanionObjectTest.show() } 复制代码
转Java之后
public final class CompanionObjectTest { @NotNull private static final String name = "爱码士"; public static final CompanionObjectTest.Companion Companion = new CompanionObjectTest.Companion((DefaultConstructorMarker)null); @Metadata( mv = {1, 1, 15}, bv = {1, 0, 3}, k = 1, d1 = {"\u0000\u001a\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0002\b\u0003\n\u0002\u0010\u0002\n\u0000\b\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002J\u0006\u0010\u0007\u001a\u00020\bR\u0014\u0010\u0003\u001a\u00020\u0004X\u0086D¢\u0006\b\n\u0000\u001a\u0004\b\u0005\u0010\u0006¨\u0006\t"}, d2 = {"Lsimple01/CompanionObjectTest$Companion;", "", "()V", "name", "", "getName", "()Ljava/lang/String;", "show", "", "kotlindemo"} ) public static final class Companion { @NotNull public final String getName() { return CompanionObjectTest.name; } public final void show() { ((CompanionObjectTest.Companion)this).getName().length(); } private Companion() { } // $FF: synthetic method public Companion(DefaultConstructorMarker $constructor_marker) { this(); } } } //调用 public static final void main() { CompanionObjectTest.Companion.show(); } // $FF: synthetic method public static void main(String[] var0) { main(); } 复制代码
所谓的伴生对象,就是伴随这出生的对象,直接在类初始化的时候,这个伴生对象Companion 也跟着实例化了,并且将伴生对象的属性变成了此类的静态变量,调用方法的时候,也是类直接调用静态属性Companion,然后再调用show方法
class Test { val I = "AAAA" // 这个不是一个内部类,所有拿不到外部类的成员 // 嵌套类 = 可以在类的里面再写一个类,但是这个类不是内部类 class Sub { fun show() { println() } class A { class B { class C { } } } } // 这个才是内部类,用inner修饰之后才是内部类 inner class Sub2 { fun show() { println(I) } } }
作者:爱码士赵Sir
链接:https://juejin.cn/post/6949031702404530189
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。