Android JAVA转Kotlin速成
前言
由于项目需要现在需要从JAVA转到Kotlin,记录一下学习过程。教材《疯狂Android讲义kotlin》。本篇不会介绍Android基础知识,着重讲解Java到Kotlin代码的变化。
在线编译网站:https://c.runoob.com/compile/2960/。一般我都是在Android Studio上面写,然后网站上面运行。
类的修饰符。
类的修饰符包括 classModifier 和_accessModifier_:
-
classModifier: 类属性修饰符,标示类本身特性。
abstract // 抽象类 final // 类不可继承,默认属性 enum // 枚举类 open // 类可继承,类默认是final的 annotation // 注解类
-
accessModifier: 访问权限修饰符
private // 仅在同一个文件中可见 protected // 同一个文件中或子类可见 public // 所有调用的地方都可见 internal // 同一个模块中可见
类定义
Java:
public class MainActivity extends AppCompatActivity {
Kotlin:
class MainActivity : AppCompatActivity() {
可以看到,继承变成了一个符号‘:’,并且可以省略权限修饰符。
属性定义
class Runoob {
var name: String = ……
var url: String = ……
var city: String = ……
}
getter,setter
lass Person {
var lastName: String = "zhang"
get() = field.toUpperCase() // 将变量赋值后转换为大写
set
var no: Int = 100
get() = field // 后端变量
set(value) {
if (value < 10) { // 如果传入的值小于 10 返回该值
field = value
} else {
field = -1 // 如果传入的值大于等于 10 返回 -1
}
}
var heiht: Float = 145.4f
private set
}
主构造器
写在class旁边,用init初始化。
class Person constructor(firstName: String) {
init {
println("FirstName is $firstName")
}
}
如果构造器有注解,或者有可见度修饰符,这时constructor关键字是必须的,注解和修饰符要放在它之前。
class People(val firstName: String, val lastName: String) {
//...
}
次构造器
写法同方法一致
class Person {
constructor(parent: Person) {
parent.children.add(this)
}
}
方法与重写
Java:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Kotlin:
override fun onCreate(savedInstanceState: Bundle?) : Unit {
super.onCreate(savedInstanceState)
可以看到,override的注解变成了修饰符。
返回值位置不再写类型,返回值类型写在方法之后。
参数需要写类型。并且语句后不再有;。
参数名称写:左边,类型写:右边。
参数类型后面的?,表示为空返回null。
继承
Kotlin所有类都继承自Any
可变长参数函数
fun vars(vararg v:Int){
for(vt in v){
print(vt)
}
}
// 测试
fun main(args: Array<String>) {
vars(1,2,3,4,5) // 输出12345
}
常量与变量
val a: Int = 1
val b = 1
val c : Int
c = 1
var x = 5
x+=1
字符串
$varName 表示变量值
${varName.fun()} 表示变量的方法返回值
var a = 1
// 模板中的简单名称:
val s1 = "a is $a"
a = 2
// 模板中的任意表达式:
val s2 = "${s1.replace("is", "was")}, but now is $a"
空指针检查机制
?、!!、?:
//类型后面加?表示可为空
var age: String? = "23"
//抛出空指针异常
val ages = age!!.toInt()
//不做处理返回 null
val ages1 = age?.toInt()
//age为空返回-1
val ages2 = age?.toInt() ?: -1
用法
fun parseInt(str: String): Int? {
return str.toIntOrNull()
}
fun printProduct(arg1: String, arg2: String) {
val x = parseInt(arg1)
val y = parseInt(arg2)
// 直接使用 `x * y` 会导致错误, 因为它们可能为 null
if (x != null && y != null) {
// 在进行过 null 值检查之后, x 和 y 的类型会被自动转换为非 null 变量
println(x * y)
}
else {
println("'$arg1' or '$arg2' is not a number")
}
}
fun main() {
printProduct("6", "7")
printProduct("a", "7")
printProduct("a", "b")
}
fun parseInt(str: String): Int? {
return str.toIntOrNull()
}
fun printProduct(arg1: String, arg2: String) {
val x = parseInt(arg1)
val y = parseInt(arg2)
// ...
if (x == null) {
println("Wrong number format in arg1: '$arg1'")
return
}
if (y == null) {
println("Wrong number format in arg2: '$arg2'")
return
}
// 在进行过 null 值检查之后, x 和 y 的类型会被自动转换为非 null 变量
println(x * y)
}
fun main() {
printProduct("6", "7")
printProduct("a", "7")
printProduct("99", "b")
}
类型检测与自动转换
fun getStringLength(obj: Any): Int? {
if (obj is String) {
// 做过类型判断以后,obj会被系统自动转换为String类型
return obj.length
}
//在这里还有一种方法,与Java中instanceof不同,使用!is
// if (obj !is String){
// // XXX
// }
// 这里的obj仍然是Any类型的引用
return null
}
区间
fun main(args: Array<String>) {
print("循环输出:")
for (i in 1..4) print(i) // 输出“1234”,4..1则不输出
println("\n----------------")
print("设置步长:")
for (i in 1..4 step 2) print(i) // 输出“13”
println("\n----------------")
print("使用 downTo:")
for (i in 4 downTo 1 step 2) print(i) // 输出“42”
println("\n----------------")
print("使用 until:")
// 使用 until 函数排除结束元素
for (i in 1 until 4) { // i in [1, 4) 排除了 4
print(i)
}
println("\n----------------")
}
比较
===比较地址,==比较数值。Kotlin没有基本数据类型,每个变量都有一个对象。
fun main(args: Array<String>) {
val a: Int = 10000
println(a === a) // true,值相等,对象地址相等
//经过了装箱,创建了两个不同的对象
val boxedA: Int? = a
val anotherBoxedA: Int? = a
//虽然经过了装箱,但是值是相等的,都是10000
println(boxedA === anotherBoxedA) // false,值相等,对象地址不一样
println(boxedA == anotherBoxedA) // true,值相等
}
类型转换
类型转换必须通过方法.toType()实现,较小类型不再是较大类型的子类型。有时候也会自动类型转换,比如long+int
toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
toFloat(): Float
toDouble(): Double
toChar(): Char
位运算
shl(bits) – 左移位 (Java’s <<)
shr(bits) – 右移位 (Java’s >>)
ushr(bits) – 无符号右移位 (Java’s >>>)
and(bits) – 与
or(bits) – 或
xor(bits) – 异或
inv() – 反向
字符
char不能与数字直接操作,必须用单引号包含起来
数组
fun main(args: Array<String>) {
//[1,2,3]
val a = arrayOf(1, 2, 3)
//[0,2,4]
val b = Array(3, { i -> (i * 2) })
//读取数组内容
println(a[0]) // 输出结果:1
println(b[1]) // 输出结果:2
}
字符串
for (c in str) {
println(c)
}
字符串模板
字符串可以包含模板表达式,用$开头。
fun main(args: Array<String>) {
val s = "runoob"
val str = "$s.length is ${s.length}" // 求值结果为 "runoob.length is 6"
println(str)
}
when
类似switch,格式为
when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
fun hasPrefix(x: Any) = when(x) {
is String -> x.startsWith("prefix")
else -> false
}
when {
x.isOdd() -> print("x is odd")
x.isEven() -> print("x is even")
else -> print("x is funny")
}
Lambda
如何理解Lambda,Lambda可以理解为一个对象,但是这个对象比较特殊,以一段代码的方式呈现。
比如 {x:Int,y:Int->x+y},->左边的为参数,右边的为函数体。
let、run、with、also、apply
这些函数叫做标准域函数,也叫拓展函数,主要是为了简化一些操作
函数 | 参数个数 | 内部访问上下文对象 | 返回值 |
---|---|---|---|
let | 1 | it | lambda最后一行代码返回值 |
with | 2 | this 或者 省略 | lambda最后一行代码返回值 |
run | 1 | this 或者 省略 | lambda最后一行代码返回值 |
apply | 1 | this 或者 省略 | 返回调用者对象 |
also | 1 | it | 返回调用者对象 |
首先我们来看一个类。
data class Book(var name: String, var author: String, var price: String){
fun adjust( value: Int){
price = price.plus(value)
}
}
fun main(){
}
然后用let去调用他,it表示参数,参数即是原方法返回值。拓展函数返回值默认为let最后一行,下面println返回unit类型,也就是java的void。
Book("《海边的卡夫卡》", "村上春树", 59)
.let {
println(it)
it.adjust(-5)
it //因为adjust()方法没有返回值,我们需要将调整价格后的Book对象作为lamda表达式的返回值返回
}
.let {
println(it)
}
用also去调用他,it表示参数,参数即是原方法返回值。拓展函数返回值默认为this,即Book。
Book("《海边的卡夫卡》", "村上春树", 59)
.also {
println(it)
it.adjust(-5) // 由于also直接返回当前对象,所以我们不用再提供返回值
}
.let {
println(it)
}
to、or、and
to用于key-value,在中间充当衔接作用,比如 key to value。
or为或位运算
and为且位运算
inline noinline crossinline
inline:通过内联(函数内容直插到调用处)的方式来编译函数,推荐高阶函数使用inline进行优化
noinline:局部关掉这个优化,来摆脱(不能把函数类型的参数当对象使用的使用)限制。
crossinline:让内联函数里的函数类型的参数可以被间接调用,代价是不能在Lambda表达式里使用return(return@label 这种形式还是可以的)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术