前言:
Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,被称之为 Android 世界的Swift,由 JetBrains 设计开发并开源。Kotlin 可以编译成Java字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。在Google I/O 2017中,Google 宣布 Kotlin 成为 Android 官方开发语言。
现在国外很多源码都采用了Kotlin语言,替代Java只是时间问题.
通俗来说,JetBrains是Kotlin的亲爹,Google是Kotlin的干爹.
Kotlin的学习网站
中文网站 https://developer.android.google.cn/kotlin/add-kotlin
觉得英文不错的可以看 https://kotlinlang.org
下面从简到难,带你进入Kotlin的世界,
- 基础语法
- 比较与数组
- 条件控制
- 循环与标签
- 类与对象
基础语法
变量
可变变量定义:var 关键字
格式:var<标识符> : <类型> = <初始值>
不可变变量定义:val 关键字
格式:val<标识符> : <类型> = <初始值>
类型推断
在Kotlin中变量的类型是省略的.如图在前面有提到Kotlin是静态语言,变量在编译期就确定了类型, 跟JS动态语言不同.
函数
普通函数定义:fun关键字
格式: fun <函数名>(var/val<标识符> : <类型>,...,var/val<标识符> : <类型> ):<返回类型>{
}
fun main() {
add(1,2)
}
fun add(number1:Int,number2:Int) : Int{
return number1 + number2
}
无返回值的函数,关键字Unit 通常可以省略
fun main() {
add(1,2)
}
fun add(number1:Int,number2:Int) : Unit{
}
函数返回值为类型推断函数
fun main() {
add(1,2)
}
fun add(number1:Int,number2:Int) = number1 + number2 //类型推断返回值为Int
可变参数函数
fun main() {
add(1,2)
}
//vararg 可变参数的关键字
fun add(vararg values:Int){
for (value in values) {
println(value)
}
}
lambda表达式函数
fun main() {
val sum = add(1,2)
println(sum)
}
//lambda表达式函数
val add:(Int,Int) -> Int = {number1,number2 -> number1 + number2 }
fun main() {
//lambda表达式函数
val add:(Int,Int) -> Int = {number1,number2 -> number1 + number2 }
val sum = add(1,2)
println(sum)
}
字符串模板
fun main() {
val name = "Zyang"
val age = 28
val info = "abcdefg"
println("name:$name ,age:$age,info:$info")
}
多行输出
带有前置空格
fun main() {
println("---------------------")
val infoMessage = """
AAAAAAA
BBBBBBB
CCCCCCC
DDDDDDD
EEEEEEE
FFFFFFF
""" // 带有前置空格
println(infoMessage)
}
去掉前置空格
fun main() {
println("---------------------")
val infoMessage = """
AAAAAAA
BBBBBBB
CCCCCCC
DDDDDDD
EEEEEEE
FFFFFFF
""".trimIndent() // 去掉前置空格
println(infoMessage)
println("---------------------")
}
去掉字符
fun main() {
println("---------------------")
val infoMessage = """
~AAAAAAA
~BBBBBBB
~CCCCCCC
~DDDDDDD
~EEEEEEE
~FFFFFFF
""".trimMargin("~") // 去掉前置空格
println(infoMessage)
println("---------------------")
}
显示特殊字符 $999.99
fun main() {
val price = """
${'$'}999.99
""".trimIndent()
println(price)
}
NULL检查机制 '?'
Kotlin的空安全设计对于声明可为空的参数,在使用时进行空判断处理.通常有两种null判断处理方式, 字段后加!! 和 另一种是字段后加?
fun main() {
var info:String? = null
println("第一种:${info?.length}")//如果info是null, 就不执行.length
println("第二种:${info!!.length}") // !! 我自己担保info 不为null,执行到此处,如果info为null 就会抛出空指针异常
if(info != null){
println(info.length) //第三种补救措施, 跟java 一样
}
}
在函数返回值中, 如果返回值返回的是null,必须在返回类型上面做有null返回的标识?
在使用这个函数的时候, 必须要做null补救措施.
区间 'in'
fun main() {
//默认是从小到大
for (i in 1..9){
println("从小到大:$i")
}
println("---------------------")
//从大到小
for (i in 9 downTo 1){
println("从大到小:$i")
}
//指定步长
for (i in 1 ..10 step 2){
println("指定步长:$i")
}
println("---------------------")
//排除最后的元素
for (i in 1 until 10){
println("排除最后元素:$i")
}
println("---------------------")
//通过in 去做if判断
val value = 99
if (value in 1..100){
println("包含在1到100之间")
}
println("---------------------")
}
执行结果比较与数组
比较两个值
fun main() {
val name1 = 1110
val name2 = 1110
// 比较值的本身, == 相当于 Java的equals, 在Kotlin中不建议使用equals, 直接用== 来代替
println("比较值的本身------")
println(name1.equals(name2))
println(name1 == name2)
// 比较对象的地址
println("比较对象内存地址------")
val test1:Int? = 1110
val test2:Int? = 1110
println(test1 === test2)
}
执行结果数组
第一种方式,开发中常用的方式
fun main() {
val numbers = arrayOf(1,2,3,4,5,6,7,8,9)
println("第一个元素:${numbers[0]}")
println("------------------------")
for (number in numbers) {
println(number)
}
}
第二种方式
在100的基础上面, 向后面加10次的1
fun main() {
val numbers = Array(10,{value:Int->(value + 100)})
for (number in numbers) {
println(number)
}
}
条件与控制
if
区间判断
fun main() {
val x = 80
val y = 20
if (x in 1..10 && y in 1..50){
println("x,y 符合")
}else{
println("x,y 不符合")
}
}
表达式比较 大小, 并返回最大值
fun main() {
val number1 = 10;
val number2 = 20 ;
val maxValue = if (number1 > number2) number1 else number2
println(maxValue)
}
表达式比较 大小, 经过逻辑处理, 并返回最大值
fun main() {
val number1 = 10;
val number2 = 20 ;
val maxValue = if (number1 > number2){
println("自己逻辑处理的代码")
number1 //必须要有返回值, 跟函数不一样, 不需要用return
}else{
println("自己逻辑处理的代码")
number2 //必须要有返回值, 跟函数不一样, 不需要用return
}
println(maxValue)
}
when相当于java中的switch
fun main() {
val number1 = 5
when(number1){
1 -> println("一")
2 -> println("二")
3 -> println("三")
4 -> println("四")
5 -> println("五")
else -> println("其他")
}
val number2 = 745
when(number2){
in 1..100 -> println("1...100")
in 100..1000 -> println("1...1000")
else -> println("其他")
}
}
另外一种方式
fun main() {
val number1 = 2
val result = when(number1){ //类型推断为String
1 -> {
println("今天星期一")
"今天星期一" //这是返回值
}
2 -> {
println("今天星期二")
"今天星期二"//这是返回值
}
3 ->{
println("今天星期三")
"今天星期三"//这是返回值
}
else -> "其他"//这是返回值
}
println("今天星期三")
}
标签与循环
标签
自定义标签,跟Java的goto一样
fun main() {
ttt@ for (i in 1..20){
for (j in 1..20){
if (i == 5){
break@ttt
}
}
}
}
类自带的标签
class Zyang {
val name = "yang"
fun show(){
println(name)
println(this.name)
println(this@Zyang.name) //这是类自带的标签
}
}
循环
val items = listOf<String>("张三", "李四", "王五")
//循环遍历
for (item in items) {
println(item)
}
items.forEach { item->
println(item)
}
//获取下标,并打印下标的值, index 是下标
for (index in items.indices) {
println("下标:$index ,对应的值:${items[index]}")
类与对象
空类
//这是一个空类, 默认就是public, final
class Empty
类的构造
主构造
class Person(id:Int) { //(id:Int) 是主构造
}
次构造
次构造里面必须要先引入主构造 ':this(id)'
class Person(id:Int) { //(id:Int) 是主构造
//这是次构造
constructor(id:Int,name:String):this(id){
}
//次构造, 构造函数重载
constructor():this(298){
}
}
fun main() {
val person = Person() //这是先调用次构造, 然后调用主构造
val person1 = Person(123) // 这是直接调用主构造
val person2 = Person(123,"张三") // 次构造
}
继承
在Kotlin 里面默认是不能继承的, 因为类默认是final. 如果想要能被继承必须要加open.
父类
open class Person(id:Int) { //(id:Int) 是主构造
//这是次构造
constructor(id:Int,name:String):this(id){
}
//次构造, 构造函数重载
constructor():this(298){
}
}
子类
class Student(id:Int) :Person(id) { //把子类的主构造id 穿给父类的主构造
}
在Kotlin中, 所有的变量都是没有默认值的,在Java中类的类的成员都是有默认值的,但是在方法内部是没有默认值必须要给类成员变量赋值,如果你要给类的成员赋值为null , 必须要给他声明?
但是在使用变量的时候, 会照成一些麻烦,这时候我们可以使用变量的懒加载,注意,懒加载的变量是不能用
val
去修饰的.懒加载变量如果没有赋值, 就不能使用, 如果使用就会抛出异常
抽象类与接口
Kotlin 的类,默认都是public final, 但是在接口 和抽象类中,都默认把open打开了.
接口
//接口默认就是open
interface Callback {
fun callbackMethod():Boolean
}
实现接口
class CallbackImpl:Callback {
override fun callbackMethod(): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
抽象类
abstract class AbstractCallback:Callback {
abstract fun getLayoutId():Int
abstract fun initView()
}
继承抽象类
在类中都是有默认的主构造,就跟Java中类中都有默认的无参构造一样. 在继承类的时候 , 必须要处理父类的主构造
class CallbackImpl:AbstractCallback() { //() 这是处理父类的主构造
override fun initView() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun getLayoutId(): Int {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun callbackMethod(): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
最终可以写成这样
class CallbackImpl:AbstractCallback() { //() 这是处理父类的主构造
override fun initView() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun getLayoutId(): Int = R.layout.main_activity
override fun callbackMethod(): Boolean = false
}
data数据类
data 类, 相当于java中的实体Bean 在java Bean 里面有get set方法, 但是在kotlin中没有get,set. data 它帮我们自动生成一个Java Bean
data class User (val id:Int,val name:String, val sex:Char)
通过AndroidStudio的Tools - Kotlin - Show Kotlin Bytecode 看到生成的java源码
public final class User {
private final int id;
@NotNull
private final String name;
private final char sex;
public final int getId() {
return this.id;
}
@NotNull
public final String getName() {
return this.name;
}
public final char getSex() {
return this.sex;
}
public User(int id, @NotNull String name, char sex) {
Intrinsics.checkParameterIsNotNull(name, "name");
super();
this.id = id;
this.name = name;
this.sex = sex;
}
public final int component1() {
return this.id;
}
@NotNull
public final String component2() {
return this.name;
}
public final char component3() {
return this.sex;
}
@NotNull
public final User copy(int id, @NotNull String name, char sex) {
Intrinsics.checkParameterIsNotNull(name, "name");
return new User(id, name, sex);
}
// $FF: synthetic method
@NotNull
public static User copy$default(User var0, int var1, String var2, char var3, int var4, Object var5) {
if ((var4 & 1) != 0) {
var1 = var0.id;
}
if ((var4 & 2) != 0) {
var2 = var0.name;
}
if ((var4 & 4) != 0) {
var3 = var0.sex;
}
return var0.copy(var1, var2, var3);
}
@NotNull
public String toString() {
return "User(id=" + this.id + ", name=" + this.name + ", sex=" + this.sex + ")";
}
public int hashCode() {
int var10000 = this.id * 31;
String var10001 = this.name;
return (var10000 + (var10001 != null ? var10001.hashCode() : 0)) * 31 + this.sex;
}
public boolean equals(@Nullable Object var1) {
if (this != var1) {
if (var1 instanceof User) {
User var2 = (User)var1;
if (this.id == var2.id && Intrinsics.areEqual(this.name, var2.name) && this.sex == var2.sex) {
return true;
}
}
return false;
} else {
return true;
}
}
}
data数据类的使用
fun main() {
val user = User(99,"李思思",'M')
val(myId,myName,mySex) = user.copy() //通过copy 拷贝一份对象
println("myId:$myId, myName:$myName, mySex:$mySex")
val(_,myName2,_) = user.copy() //通过copy 拷贝一份对象, _ 不接受这个参数
println(" myName2:$myName")
}
object单例类
//只实例一次 , 相当于单例
object ObjectDemo {
fun funM(){
println("fuM")
}
}
fun main() {
ObjectDemo.funM()
ObjectDemo.funM()
ObjectDemo.funM()
ObjectDemo.funM()
ObjectDemo.funM()
}
Kotlin内部类 inner
class ClassDemo {
val I = "AAAA"
//这个不是一个内部类,这只是嵌套类, 所以拿不到外部成员
class Sub{
fun show(){
println(I) //编译报错, 拿不到 I 这个值
}
}
//真正的内部类
inner class Sub2{
fun show(){
println(I)
}
}
}
Kotlin单例模式
companion object 派生,随着类的加载而存在,相当于Java中类中的static
单例模式1,Kotlin版
class NetManager {
//派生操作
companion object{
//全部相当于java中的static
fun getInstance():NetManager = Holder.instance
}
object Holder{
val instance = NetManager()
}
fun show(name:String){
println("show:$name")
}
}
fun main() {
val net = NetManager.getInstance()
net.show("kt Zyang")
}
单例模式2,Kotlin版
class NetManager {
//派生操作
companion object{
private var instance:NetManager? = null
fun getInstance():NetManager{
if (instance == null){
instance = NetManager()
}
return instance!!
}
}
fun show(name:String){
println("show:$name")
}
}
fun main() {
val net = NetManager.getInstance()
net.show("kt,Zyang")
}
Kotlin 关于高阶函数,与协程 属于Kotlin进阶内容, 在后面会有专门的文章去介绍这部分内容.