Kotlin运行原理
java虚拟机并不是和编写的java代码打交道,而是处理编译之后的class文件
Kotlin使用了新的编译规则生成class文件,只要class文件的符合规范java虚拟机就可以识别。
Kotlin的优势
1.Kotlin语法更加简洁,代码量可能会减少50%
2.Kotlin增加了很多高级语法特性,使得开发效率大大提升
3.Kotlin在语言安全性上方面下了很多功夫,几乎杜绝了空指针这个崩溃率最高的异常。
4.Kotlin和java 100%兼容,可以无缝只用java的三方库
var 与 val
var表示可变的变量 variable的简写
val 表示不可变的变量相当于final value的简写
使用这种定义变量的方式,那么编译器是怎么知道类型的这个得益于kotlin具有出色的类型推到机制
==优先使用val 声明变量,当这个不能满足的时候再使用var==
定义函数的方式
fun add(a:Int,b:Int):Int{
return a+b;
}
add是函数名,括号里边的是参数,格式是:参数名:参数类型,如果不需要输入参数可以是一个空括号。
括号后边的是是返回值的类型,没有就不用写。语句的后边不需要添加分号
Kotlin的内置函数
fun largeNumber(a:Int,b: Int):Int{
return max(a,b)
}
max就是kotlin的内置函数
Kotlin语法糖
当一个函数只有一行代码的时,Kotlin允许我们不必写函数体,可以直接将唯一的一行代码写在函数定义的尾部,中间使用等号连接即可,如上边的函数可以使用这个方式进行编写。
fun largeNumber(a:Int,b:Int):Int= max(a,b)
条件语句有两种实现方式:if和when。
if条件语句
Kotlin的if和java几乎是没有区别的,不同之处在于kotlin中的if多了一个额外的功能:可以有返回值的,返回值就是if语句每一条件的最后一行代码的返回值,如下面这个写法
fun largeNumber(a:Int,b:Int):Int{
return if (a>b){
a
}else{
b
}
}
根据语法糖可以进一步精简
fun largeNumber(a:Int,b:Int):Int=if (a>b)a else b
这个就是kotlin 代码简洁的例子
when条件语句
when语句有点类似于java中的switch语句,但是比switch语句强大。
fun getScore(name:String) = when(name){
"tom"->84
"lili"->82
"jack"->85
"tong"->86
else->0
}
省去了if判断,简洁清爽。
when语句还支持类型判断
fun checkType(num:Number):String{
return when (num) {
is Int -> "is int"
is Double -> "is double"
else -> "error type"
}
}
类型判断代码中,is关键字就是类型匹配的核心,它相当于java 的instanceof关键字。Number 是kotlin内置的一个抽象类,Int、Long、Float、Double都是它的子类。
kotlin中判断字符串或者对象是否相等可以直接使用==,不用调用equals()方法。
循环语句
kotlin中跟java一样也提供了两种循环语句:while和for循环,while和java的完全一样。
其中对for循环做了很大幅度的修改,java中使用的for-i 循环在kotlin中别舍弃了,for-each被加强变成了for-in循环
kotlin 表示一个区间
val range=0..10; //[0,10]
这个表示方式,两端都会包含
val range=0..10; //[0,10]
for (i in range){
println("i=$i");
}
上面的方式在当成数组的下标的时候不方便,因为最后一个数字是不包含的,可以采用这个方式
val range=0 until 10; //[0,10) 这个是左闭右开的
这样就不包含最后的10了
for (i in range step 2){
println("i=$i");
}
step 这个可以在循环的时候跳过某些元素
如果想创建一个降序的空间
val down=10 downTo 1 //[10,1]
Kotlin 面向对象
下面创建一个类
class Person {
var name=""
var age=0
fun eat(){
println(name+"is eating. he is "+age+"years old.")
}
}
//实例化调用这个类
fun main(){
val p=Person(); //声明一个对象
p.name="tom"
p.age=10
p.eat()
}
kotlin本着最简化的设计原则,把new关键字和分号都省了
面向对象的一个重要的特性-继承
open class Person {
var name=""
var age=0
fun eat(){
println(name+"is eating. he is "+age+"years old.")
}
}
class Student : Person() { //
var studentNumber = 0 //学号
var grade=0 //年级
}
上面写了一个Student 类继承Person类,继承只需要使用:就可以,不用再使用extends 关键字。
注意:Person类的声明变化,类前面加了一个open的关键字,如果不加这个关键字是不能被继承的。
在kotlin中所有的非抽象的类默认都是不允许被继承的,相当于java中给类加了一个final关键字。
继承本身带有侵入性,按照依赖倒置的原则,高层模块不应该继承底层模块都应该继承抽象的语义,好多时候java中没有这个语法限制,常常会违背这个设计原则。如果一个类不是专门为继承设计的,那么就应该主动加上final关键字,禁止它被继承。
这里还有一个点,就是父类后边的括号,为什么需要加括号?这里就涉及到kotlin中 主构造函数、次构造函数等方面的内容。
主构造函数将会是最常用的构造函数,每个类都会有一个默认的无参主构造函数,主构造函数的特点是没有函数体,直接定义在函数的后边。
class Student( val studentNumber:Int, val grade:Int) : Person() {
init {
println("studentNumber is $studentNumber")
println("grade is $grade")
}
}
上面这个写法就相当于声明了主构造函数的带两个参数的,kotlin还提供了init结构体,所有主构造函数的逻辑可以写在里面。
这些跟父类的括号有什么关系呢,这就涉及java 继承特性的一个规定,子类的构造函数必须调用父类的构造函数。可是主构造函数并没有函数体,就没办法调用父类的构造函数了。有一个方法就可以放在init方法,好多情况下是不需要写init结构体的。
所以这里的括号就是子类主构造函数调用父类的那个构造函数,在继承的时候使用括号来指定。
次构造函数一般用不到,次构造函数跟主构造函数的区别是:次构造函数有函数体。
kotlin规定,当一个类既有主构造函数,也有次构造函数的时候,次构造函数必须调用柱构造函数。
次构造函数使用constructor进行定义。
class Student( var studentNumber:Int, var grade:Int) : Person() {
//这个结构体,专门用于构造函数的调用
init {
println("studentNumber is $studentNumber")
println("grade is $grade")
}
//这个是次构造函数
constructor(studentNumber:Int):this(studentNumber,0)
//这个是次构造函数
constructor():this(0)
}
另外kotlin还允许自由次构造函数,没住构造函数的情况,这个情况父类的括号可以省了,由于没有主构造函数,次构造函数只能直接调用父类的构造函数
class Student : Person {
//这个是次构造函数
constructor(studentNumber:Int):super(){
println("studentNumber is $studentNumber")
}
}
kotlin中的接口
java中可以是单继承,可以有多个实现。kotlin也是这样的。
open class Person(name:String, age:Int) {
var name=name
var age=age
fun eat(){
println(name+"is eating. he is "+age+"years old.")
}
}
class Student( name:String, age:Int) : Person(name,age),Study {
override fun readBooks() {
println("$name is read books")
}
}
kotlin中实现一个接口,不再使用implements 这个关键字,统一使用冒号和逗号。
使用override关键字来重写父类或者接口中的函数。
另外kotlin还允许接口中定义默认实现,拥有了默认实现就不要求实现类必须重写这个方法了,可以选择重写。
kotlin类的可见性
修饰符 | java | kotlin |
---|---|---|
public | 所有类可见 | 所有类可见(默认) |
private | 当前类可见 | 当前类可见 |
protected | 当前类、子类,同一个包下的可见 | 当前类、子类 |
default | 同一包下面的类可见(默认) | 无 |
internal | 无 | 同一个模块的类可见 |
internal是kotlin新增的一个关键字,这个是同一个模块中的类可见,应用场景:当我们开发一个模块给别人使用,有一些类只想内部调用,不想外部调用就可以使用这个关键字进行函数声明。
kotlin的数据类
java 声明一个数据实体类
public class CellPhone {
String brand;
double price;
public CellPhone(String brand, double price) {
this.brand = brand;
this.price = price;
}
@Override
public boolean equals(Object o) {
if (o instanceof CellPhone){
CellPhone other= (CellPhone) o;
return other.brand.equals(brand)&&other.price==price;
}
return false;
}
@Override
public int hashCode() {
return (int) (brand.hashCode()+price);
}
@Override
public String toString() {
return "CellPhone{" +
"brand='" + brand + '\'' +
", price=" + price +
'}';
}
}
重写了equals 和hashCode方法,有的时候不重写,当使用hashMap和hashCode的时候会有问题,toString是为了打印日志。
kotlin声明一个数据实体类
data class CellPhone(val brand:String, val price:Double)
一行搞定了,不管是打印数据还是使用HashMap和HashCode 都不会有问题。就是因为使用data关键字,就表明希望这个类是一个数据类,kotlin就把equals、hashCode、toString这些方法自动生成了,从而简化开发工作量。当类中没有别的实现,大括号也可以省略。
kotlin中的单例设计模式
java中的单例有饱汉式、饿汉式、双检测、匿名内部类、枚举等实现方式。
下面看kotlin的单例实现方式
object SingleTon {
fun test(){
println("单例测试")
}
}
只需要将class关键字改成object ,使用这个关键字kotlin就会帮我们创建一个SingleTon的实例,并保证全局只有一份实例。
上面分享的这些内容,学习郭霖的书籍总结而来,希望能给初学者带来帮助,共同进步,共同成长。