A同学:没有对象,好孤单啊,怎么办?
B同学:new 一个不就好了嘛!
这是一个网络段子,也算是工(程)程(序)师(猿)的一种独特的对话。对象,在程序世界一般指实际可操作的主体,是某抽象的具体化实例。比如我们的游戏角色,我们可以理解为一对象,其实是在角色基础上针对特定用户进行的一个具例,有所有角色的共性,也有单一角色的个性。
在Kotlin中也离不开对象,但又有其独特的语法。Let`s go!
一 类对象
1.1 Object关键字产生单例
object ApplicationConfig{
init {
println("ApplicationConfig init")
}
fun doSomething(){
println("doSomething")
}
}
println(ApplicationConfig)
ApplicationConfig.doSomething()
println(ApplicationConfig)
//结果
ApplicationConfig init
ApplicationConfig@330bedb4
doSomething
ApplicationConfig@330bedb4
使用Object修饰的类对象是一个单例类,不可进行常规的new操作。通过输出结果我们可以看到只在第一次调用的时候进行了初始化操作,后续的操作都是对应的同一对象。那它为什么可以产生这样一个单例呢,我们看下编译后的代码:
public final class ApplicationConfig {
public static final ApplicationConfig INSTANCE;
public final void doSomething() {
String var1 = "doSomething";
boolean var2 = false;
System.out.println(var1);
}
private ApplicationConfig() {
}
static {
ApplicationConfig var0 = new ApplicationConfig();
INSTANCE = var0;
String var1 = "ApplicationConfig init";
boolean var2 = false;
System.out.println(var1);
}
}
是不是有种很熟悉的感觉,这不就是java中单例的一种写法么。在java中需要那么多的代码才能实现的,在kotlin中通过一个关键字实现了,有意思。
1.2 对象表达式
有时候你不一定非要定义一个新的命名类,也许只是需要某个类的一种变体,而且也只会使用一次。对于这种场景,实际是连命名都可以省略的。对象表达式是XX的子类,这个匿名类依然遵循object关键字的一个规则,即一旦实例化,该匿名类只能有唯一一个实例存在。
open class Player0{
open fun load() = "loading something"
}
val player0 = object :Player0(){
override fun load(): String {
return "loading another"
}
}
//结果
loading another
新的类连名称都没有,就生成了一个唯一的对象。
1.3 伴生对象
在java中,我们可以通过static关键字对外提供静态属性或者静态方法。这时候我们可以通过类名直接进行调用,但在kotlin中是没有static关键字的,那我们如何完成类似的功能呢?这时候我们可以使用伴生对象来完成,使用companion object来进行伴生对象的声明,一个类里只能有一个伴生对象。
class ConfigMap{
companion object{
var data = 9999
fun load(){
println("load $data")
}
}
}
println(ConfigMap.data)
ConfigMap.data = 99999
ConfigMap.load()
//结果
9999
load 99999
1.4 嵌套类
如果一个类只对另一个类有用,那么将其嵌入到该类中并使这两个类保持在一起是合乎逻辑的,可以使用嵌套类。
class Player1{
class Equipment(var name:String){
fun show() = println("equipment ${name}")
}
fun battle(name:String){
Equipment("sharp knife $name").show()
}
}
Player1.Equipment("AK").show()
1.5 数据类
数据类是专门设计用来存储数据的类,数据类提供了toString的个性化实现,==符号默认情况下,比较对象就是比较他们的引用值,数据类提供了equals和hash code的个性化实现。
data class Coordinate(var x:Int,var y:Int){
val isInBounds = x > 0 && y > 0
}
val coordinate0 = Coordinate(10,20)
println(coordinate0)
println(coordinate0 == Coordinate(10,20))
//使用copy来快速复制构建
val coordinate1 = coordinate0.copy(11)
println(coordinate1)
//解构
val (x,y) = Coordinate(100,200)
println("$x,$y")
//结果
Coordinate(x=10, y=20)
true
Coordinate(x=11, y=20)
100,200
关于解构,就是在后台声明component1、conponent2等若干个组件函数,让每个函数负责管理你想返回的一个属性数据,如果你定义一个数据类,它会自动为所有定义在主构造函数的属性太你家对于的组件函数。对应编译后的代码可以看得更清晰:
public final int component1() {
return this.x;
}
public final int component2() {
return this.y;
}
1.6 枚举类
枚举类,用来定义常量集合的一种特殊类,定义与java中类似,也使用enum关键字。
enum class Direction(private val coordinate: Coordinate){
EAST(Coordinate(1,2)),
WEST(Coordinate(3,4)),
SOUTH(Coordinate(5,6)),
NORTH(Coordinate(7,8));
fun updateCoordinate(coordinate: Coordinate) =
Coordinate(coordinate.x + this.coordinate.x,coordinate.y+this.coordinate.y)
}
println(Direction.EAST.updateCoordinate(Coordinate(5,5)))
//结果
Coordinate(x=6, y=7)
1.7 运算符重载
操作符 | 函数名 | 作用 |
---|---|---|
+ | plus | 把一个对象添加到另一个对象里 |
+= | plusAssign | 把一个对象添加到另一个对象里,然后将结果赋值给第一个对象 |
== | equals | 如果两个对象相等,返回true,否则返回false |
> | compareTo | 如果左边的对象大于右边的对象,则返回true,否则返回false |
[] | get | 返回集合指定位置的元素 |
… | rangeTo | 创建一个range对象 |
in | contains | 如果对象包含在集合里,则返回true |