kotlin学习笔记
val与var
val: 不可变变量,赋值以后不能修改,相当于java中的final
var: 可变变量
变量与类型
kotlin中一切皆对象
val a = 100
val b : Int = 100
kotlin中支持类型推导,也就是相当于
val int = 100 //推导为Int类型
val long = 1234567L //必须加L后缀才会推导成Long类型
val double = 13.14 //推导为Double类型
val float = 13.14F //必须加F后缀才会推导成Float类型
val hex = 0xAF //使用“0x”,来代表十六进制字面量
val binary = 0b01010101 //使用“0b”前缀,来代表十六进制字面量
在kotlin中,无法像java那样,可以强制类型转换,他是像下面这样,这也体现了一切皆对象的思想
val a = 1
val i: Double = a.toDouble()
kotlin中提供了一个字符串模板:
val in = "world"
val out = "Hello $in !"
// 输出结果:Hello World!
同时Kotlin中还可以用一个变量简单的标识多行文字
val a = """
这是第一行
这是第二行
这是第三行 """
val a = arrayof("1","2")
kotlin中声明一个列表要使用listof()
,但是这个列表无法添加新的元素,要使用mutableListOf()
声明的列表才可以进行添加元素。我认为这和kotlin中的推荐有关——“编程中尽量多使用不变元素”
val a = listof("1","2")
a.add("3") //此时会报错
val b = mutableListOf("1","2")
b.add("3") //此时不会报错
空安全
在Kotlin中,处理可能为空的值时,需要使用一些特殊的操作符和注解。
- kotlin中所有类型默认都是非空的,在声明的时候,如果他可能为空,就需要在类型后面加一个
?
var str: String? = "Hello" // 声明一个可空的字符串类型
- 安全调用操作符(Safe Call Operator): 如果左边的表达式不为空,它会执行调用的方法,否则返回null。
var str: String? = "Hello"
println(str?.length) // 如果str不为空,则打印长度,否则打印null
- Elvis操作符: 如果左边的表达式不为空,它会执行调用的方法,否则返回右边的表达式的值。
var str: String? = "Hello"
println(str?.length ?: 0) // 如果str不为空,则打印长度,否则打印0
- 非空断言操作符(Non-null Assertion Operator): 告诉编译器该变量一定不为空,如果为空会抛出异常。
var str: String? = "Hello"
println(str!!.length) // 如果str为空,会抛出KotlinNullPointerException
- 安全转换操作符(Safe Casts Operator): 在继承关系中安全地将对象转换为子类型。
val any: Any = "Hello"
val str = any as? String
println(str?.length) // 如果转换成功,则打印长度,否则打印null
object关键字
在kotlin中,object关键字,却有三种迥然不同的语义,分别可以定义:匿名内部类、单例模式、伴生对象。Kotlin的设计者认为,这三种语义本质上都是 在定义一个类的同时还创建了对象,所以将其统一成一个关键字:object
什么是匿名内部类?
- 匿名内部类(Anonymous Inner Class)在 Java 中是一种特殊的内部类,它没有名字,可以在代码中临时创建,并且通常用于实现接口或继承类的实例。
Java中的匿名内部类:
public interface OnClickListener {
void onClick(View v);
}
image.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
gotoPreview();
}
});
这就是典型的匿名内部类的写法,View.OnClickListener是一个接口,因此我们在创建它的时候,必须 实现它内部没有实现的方法。
同样的,在kotlin中,也有匿名内部类的说法,但是java中是使用 new
来实现一个匿名内部类,而kotlin中则是使用 object
关键字,来新建匿名内部类
image.setOnClickListener(object: View.OnClickListener {
override fun onClick(v: View?) {
gotoPreview()
}
})
Java和Kotlin相同的地方就在于,它们的接口与抽象类,都不能直接创建实例。想要创建接口和抽象类的实例,我们必须通过匿名内部类的方式。
不过,在Kotlin中,匿名内部类还有一个特殊之处,就是我们在使用object定义匿名内部类的时候,其实还可以 在继承一个抽象类的同时,来实现多个接口。
interface A {
fun funA()
}
interface B {
fun funB()
}
abstract class Man {
abstract fun findMan()
}
fun main() {
// 这个匿名内部类,在继承了Man类的同时,还实现了A、B两个接口
val item = object : Man(), A, B{
override fun funA() {
// do something
}
override fun funB() {
// do something
}
override fun findMan() {
// do something
}
}
}
在日常的开发工作当中,我们有时会遇到这种情况:我们需要继承某个类,同时还要实现某些接口,为了达到这个目的,我们不得不定义一个内部类,然后给它取个名字。但这样的类,往往只会被用一次就再也没有其他作用了。
在 Java 中,类是单继承的,这意味着一个类只能继承一个父类。如果我们想要在继承某个类的同时实现接口(尤其是多个接口),通常要:
- 创建一个新的类,继承目标类;
- 在新类中实现需要的接口;
- 这个新类仅用于特定场景,且没有通用性,可能用完这一次就再也不用了。
为了满足这些需求,我们不得不给这个新类取个名字,即使它只会使用一次。这样做不仅代码显得冗余,还可能让类文件变得杂乱。例如:
// 需要继承SomeClass,同时实现SomeInterface
class MyTempClass extends SomeClass implements SomeInterface {
@Override
public void someMethod() {
// 实现逻辑
}
}
如果在代码中,这个 MyTempClass
仅用在一个特定的场景里,以后也不会再复用,为它命名和定义一个类就显得有些多余。
在Kotlin中,通过 object
,可以同时继承类并实现接口,不用额外创建新类,也不需要命名。我们可以在用到的地方直接创建它。
val instance = object : SomeClass(), SomeInterface {
override fun someMethod() {
// 实现逻辑
}
}
在这段代码中:
object
表达式直接创建了一个继承SomeClass
并实现SomeInterface
的匿名对象。- 不需要命名或创建新类文件。
- 仅在需要的地方创建和使用,用完即抛。
这个对象没有名字,也不需要额外定义一个类文件,在代码中它是匿名的,且可以直接继承和实现想要的父类或接口。这样做避免了冗余类的定义,让代码更加简洁,不必再为一次性用的类命名或管理。
Java单例模式可以查看文章Java设计模式学习笔记
- 感谢你赋予我前进的力量