Java转Kotlin指北

前言

  • Java实际上是一种解释性语言. Java源代码编译后, 生成能被JVM执行的class文件.
  • Kotlin编译器生成的文件能被JVM识别并执行, 所以即使KT的语法和Java相差甚远, 仍可以在相同的环境下执行.
  • Kotlin是简化版补强版的Java, 而且支持了很多高级语言的特性.
  • Kotlin简化了很多Java中多余的语法, 比如: Kotlin中每一语句后都不需要加;

变量

声明

KT和java声明变量很不一样. KT有类型推导机制, 所以可以不写类型.

//val即value,代表常量,对应java中加final的变量
val a = 10
//var即variable,代表变量
var b = 10

//但如果要延时初始化,那么就需要加类型了,因为此时无法推导
val a:Int
var b:Int

为什么要有var和val?

  • 在Java中一个变量默认可变, 加上fianl后才不可变. 这就有变量被改了(本不改该)而发生问题的风险. 加上fianl可以避免这个风险, 但由于其并非是强制的, 所以很少程序员会主动加.
  • 使用KT这种形式, 就必须要在意这个问题, 从而规避了这个风险.
  • 一个好的声明习惯是: 一个变量优先声明成val, 后面遇到要修改的情况,在修改成var.

类型

  • Java中有基本数据类型和其对应的包装类. KT则完全抛弃了基本数据类型, 都是对象.
Java基本数据类型 Kotlin对象数据类型 说明
int Int 整型
long Long 长整型
short Short 短整型
float Float 单精度浮点型
double Double 双精度浮点型
boolean Boolean 布尔型
char Char 字符型
byte Byte 字节型

函数

  • 与Java不同, KT中的函数需要fun关键字进行标注.
  • 与Java相同, 括号里面填写参数, 没有参数只留一对括号即可. 与Java不同, 参数声明是格式"参数名:参数类型"
  • 函数返回值写在)后面, 和参数声明类似的格式:返回值类型,如果没有返回值, 这部分可以直接省略
fun largerNumber(num1: Int, num2: Int): Int {
    
    
    return max(num1, num2)
}
//当函数中只有一行时,可以不用写大括号, 直接写=,return也可以省略,简化↓
fun largerNumber(num1: Int, num2: Int): Int = max(num1, num2)

//使用这个语法糖时, 返回值类型也是可以确定的,返回值类型也可以省略,简化↓
fun largerNumber(num1: Int, num2: Int) = max(num1, num2)

参数默认值

  • 设置默认值后, 不强制要求填写该参数
//在参数后面加=号,写上值, 这就是该参数的默认值
fun printParams(num: Int, str: String = "hello") {
    
    
    println("num is $num , str is $str")
}
  • 如果第一个参数有默认值, 不想传入怎么办? KT支持键值对传参, 不一定要按顺序. 从而解决.
//键值对传参,避免顺序传参的类型不匹配
printParams(str = "world", num = 123)

逻辑控制

  • 在Java中, 有表达式和语句的区别, 前者可以给变量赋值, 后者则不行.
  • 但在KT中, 表达式和语句的界限模糊了, 很多KT中的语句都会有返回值, 从而变成一个表达式. 可以用于变量的赋值.

if语句

  • if语句每个条件的最后一行代码会作为返回值返回.
fun largerNumber(num1: Int, num2: Int): Int {
    
    
    val value = if (num1 > num2) {
    
    
        num1
    } else {
    
    
        num2
    }
    return value
}

//使用上面提到的语法糖,简化↓
fun largerNumber(num1: Int, num2: Int) = if (num1 > num2) num1 else num2

when语句

  • 可以理解为Java中switch语句的加强版:
    1. 自带break;
    2. 可以传任意类型的参数, 甚至不带参数;
    3. 支持类型匹配;
//精准匹配
when (type) {
    
    
    "1" -> {
    
    
		1
	}
    "2" -> {
    
    
    	2
    }    
    //只有一行可以省略大括号
    "3" -> 3
    else -> {
    
    
    	//else相当于switch的default
		0
	}
}
//类型匹配,is相当于Java的instanceof
   when (num) {
    
    
   //判断num的类型,并打印
       is Int -> println("number is Int")
       is Double -> println("number is Double")
       else -> println("number not support")
   }


/*
不带参数用法, 把判断表达式完整写在->前
由于是判断表达式, 所以非常灵活, 可以代替多重ifelse.
*/
when {
    
    
    type < 1 -> {
    
    
		"1"
	}
    type == 2 -> {
    
    
    	"2"
    }    
    type == 3 -> "3"
    else -> {
    
    
		0
	}
}

循环语句

  • java的for-i循环即for(;;)被KT舍弃了
  • java的for-each循环在KT则大幅加强变成for-in循环

for-in 循环与区间

  • 为了方便的使用for-in循环, KT有生成特定范围语法——区间

两端闭区间

//数学表示[0,10]
val range = 0..10
 for (i in range) {
    
    
     println(i)
 }

左闭右开区间

//数学表示[0,10)
val range = 0 until 10
  • 常用于遍历数组, 右边界是长度即可

降序区间

//倒序打印10到1
 for (i in 10 downTo 1) {
    
    
     println(i)
 }

规律跳过一些元素

//1到10(不包括10), 每次循环加2, 相当于for-i循环中i = i + 2
 for (i in 0 until 10 step 2) {
    
    
     println(i)
 }

repeat 循环

  • 简单的次数循环
//定义循环次数
var time = 3
repeat(time)
{
    
     index ->
    println(index)
}

类与对象

实例化

  • 简化, 去掉了关键字new, 因为调用一个类的构造函数肯定就是要创建它的实例, 没必要用new额外标明.
//实例化
val p = Person()

继承

  • KT的类默认是不能继承的(相当于Java中加了final的类), 原因和变量声明类似.
  • 要在class前加上open关键字, 才能让KT的类被继承.
//定义一个可被继承的Person类
open class Person {
    
    
	var name = ""
}

//KT中采用:代替extends作为继承关键字
class Student : Person() {
    
    
    var grade = 0
}

类构造函数

主构造函数

  • 最常用的构造函数
  • 特点:
    1. 每个类只能有一个主构造函数
    2. 类默认有一个不带参数的主构造函数
    3. 可以添加参数
    4. 没有函数体
//在Student类中传入name和grade作为主构造函数的参数
class Student(val name: String, val grade: Int) : Person() {
    
    
}
  • 传入的参数可以直接初始化, 所以可以定义为val.
  • 如果想在主构造函数中执行逻辑,可以在init结构体中写
class Student(val name: String, val grade: Int) : Person() {
    
    
    init {
    
    
    	//在初始化时打印参数
        println("name is " + name)
        println("grade is " + grade)
    }
}
  • 可以注意到, 继承中父类名后面还有一个(),其实这里就指定了子类的主构造函数调用父类的哪个构造函数.

次构造函数

  • 很少用, 因为KT有参数默认值的语法, 基本可以取代次构造函数.
  • 特点:
    1. 一个类可以有多个次构造函数
    2. 使用constructor关键字来定义
    3. 当有主构造函数时, 次构造函数必须调用主构造函数
    4. 有函数体
class Student(val sno: String, val grade: Int, name: String, age: Int) :Person() {
    
    
    //通过this调用主构造函数
    constructor(name: String, age: Int) : this("", 0, name, age) {
    
    
    }

    constructor() : this("", 0) {
    
    
    }
}
  • 当类没有显示定义主构造函数而且定义了次构造函数时, 它就是没有主构造函数的. 所以, 不需要加父类名后面加一个().
//类后面没有括号(),没有定义主构造函数
class Student : Person {
    
    
	//使用constructor定义次构造函数, 但没有主构造函数,不能用this,只能用super来用父类的主构造函数
    constructor(name: String, age: Int) : super(name, age) {
    
    
    }
    //该类没有主构造函数
}

接口

  • 与Java与一致: 单继承,多实现
  • 定义方法和Java一致
  • 实现接口时, 也是使用冒号:,中间用逗号,进行分隔
//定义接口
interface Study {
    
    
    fun readBooks()
    fun doHomework()
}

//Student类继承Person类
class Student(name: String, age: Int) : Person(name, age), Study {
    
    
	//使用overvide关键字代表重写方法
    override fun readBooks() {
    
    
        println(name + " is reading.")
    }

    override fun doHomework() {
    
    
        println(name + " is doing homework.")
    }
}

接口方法默认实现

  • KT支持对接口的函数进行默认实现, 默认实现的接口不强制要求重写. Java在JDK 1.8之后也开始支持这个功能了.
  • 复用更容易, 如果只能抽象方法, 只能将接口改成抽象类, 但单继承的限制, 导致该方法有时行不通.
interface Study {
    
    
    fun readBooks()

    fun doHomework() {
    
    
        println("do homework default implementation.")
    }
}

函数可见性修饰符

可见性修饰符 Kotlin Java 差别
public 所有类可见(默认) 所有类可见 KT默认是public
private 当前类可见 当前类可见 相同
protected 当前类、子类可见 当前类、子类、同一包路径下的类可见 KT范围小了,同包不可见
default 同一包路径下的类可见(默认) Java独有
internal 同一模块中的类可见 KT独有

数据类

  • 数据类很常用, MVC、MVP、MVVM等架构模式中的M就是指数据类.
  • 数据类一般需要重写equals()、hashCode()、toString()这几个方法. 对于Java来说这些都需要手动生成; KT有专门的数据类, 自动实现上面功能,避免写这些功能代码.
  • class前加上open关键字即可把类变成数据量.
//类中没有代码时, 可以省略大括号
data class phone(val brand: String, val model: String)

单例类

  • 单例模式非常常用, Java中要实现单例模式需要较多的代码, 但对于KT, 只需将class关键字改成object关键字即可,KT会自动保证其是个单例.
  • 调用单例类的方法和Java调用静态方法相似.
//定义单例类
object Singleton {
    
    
    fun singletonTest() {
    
    
        println("singletonTest is called.")
    }
}
//调用单例类方法
Singleton.singletonTest()

字符串内嵌表达式

  • java中要在字符串中显示变量只能采用+号连接. 这种写法费力而且易错.
  • KT支持类似C语言printf(),通过在字符串里嵌入${}这种语法结构的表达式来显示变量的值.
"hello, ${
      
      obj.name}. nice to meet you!"
//当表达式中只有一个变量时,可以把大括号省略,↓
"hello, $name. nice to meet you!"
"Cellphone(brand=$brand, price=$price)"

参考资料
第一行代码——Android(第3版)
repeat循环

猜你喜欢

转载自blog.csdn.net/Reven_L/article/details/120418803