Kotlin面向对象总结(Any、Any?、Nothing、自动装箱与拆箱、数组类型)

Java并不能在真正意义上被称作一门“纯面向对象”语言,因为它的基本类型与函数并不能看作对象。

在Kotlin类型系统中,并不区分基本数据类型与包装类型。

 

Kotlin类型结构图(选取String、Int、自定义类型)

 

Any;非空类型的根类型

与Object作为Java类层级结构的顶层类似,Any类型是 Kotlin 中所有非空类型的超类。

对于Kotlin 来说,如果定义了一个没有指定父类型的类型,则该类型将是Any的直接子类型。如果定义了父类型,那么该父类型是该类的直接父类型,但是新类型的最终根类型为Any。

Kotlin的Type Checker强制检查了父子关系。例如,你可以将子类型值存储到父类型变量中。但是不能将父类型值存储到子类型中。

Kotlin把Java方法参数和返回类型中用到的Object类型看作Any(更准确的说是“平台类型”)。当在Kotlin函数中使用Any时,它会编译成Java字节码中的Object。

 

什么是平台类型?

平台类型本质上是Kotlin不知道可空性信息的类型,所有Java 引用类型在Kotlin中都表现为平台类型。当在Kotlin中处理平台类型的值的时候,它既可以被当作可空类型来处理,也可以被当作非空类型来操作。

 

Any?:所有类型的根类型

Any是所有非空类型的根类型,Any?才是所有类型(可空和非空类型)的根类型。

 

什么才是子类型化?

从Java来看:继承关系决定父子类型关系。

“继承”和“子类型化”是两个完全不同的概念。子类型化的核心是一种类型的替代关系,可表示为:

S<:T

S是T的子类,这意味着在需要T类型值的地方,S类型的值同样适用。如在Kotlin中Int是Number的子类:

fun printNum(num: Number) {
    println(num)
}

fun main() {
    val n: Int = 1
    printNum(n)
}
1

 

作为比较,继承强调的是一种“实现上的复用”,而子类型化是一种类型语义的关系,与实现没有关系。

像Java,由于在声明父子类型关系的同时也声明来继承的关系。

所以在Kotlin中,虽然Any与Any?没有继承关系,然而在使用Any? 类型值的地方,显然可以传入一个类型为Any的值。反之,就不行。

 

Any? 与Any??

如果Any?是Any的父类型,那么Any?? 是否又是Any?的父类型,如果成立,是否意味着就没有所谓的所有类型的根类型了?

在Kotlin 中,可空类型可以看作是所谓的Union Type,近似于数学中的并集。如果用类型的并集来表示Any?可写为Any U Null。

相应的Any??就可以表示为Any U Null U Null,等价于Any U Null,即Any??等价于Any?。因此,说Any?是所有类型的根类型是没有问题的。

 

Nothing与Nothing?

abstract class Animal(val weight: Double)
class Bird(weight: Double, val flightSpeed: Double) : Animal(weight)
class Fish(weight: Double, val swimmingSpeed: Double) : Animal(weight)

 

在Kotlin类型层级结构的最底层是Nothing类型。加上Nothing类型之后,类型结构图如下:

 

Nothing是没有实例的类型。Nothing类型的表达式不会产生任何值。需要注意的是:任何返回值为Nothing的表达式之后的语句都是无法执行的。Kotlin中retrun、thorw等(流程控制中与跳转相关的表达式)返回值都为Nothing。

Nothing对应的Nothing?,可以从字面上解释为:可空的空。与Any、Any?类似,所以Nothing?是Nothing的父类型,所以Nothing处于Kotlin类型

层级结构的最低层。它只能包含一个值:null,本质上与null没有区别。所以可以使用null作为可空类型的值。

 

 

自动装箱与拆箱

Koltin中没有int、double、float、long等基本数据类型,取而代之的是引用类型包装类Int、Float、Double、Long。

除了代表数值的类型,还有布尔(Boolean)、字符(Char)、字符串(String)及数组(Arry)。

 

但是只能说Kotlin比Java更接近纯面向对象的设计。

因为:

Kotlin代码

val x1:Int = 10

val x2:Int? =12

转Java代码

public final class TestIntDemoKt {
   private static final int x1 = 10;
   @Nullable
   private static final Integer x2 = 12;

   public static final int getX1() {
      return x1;
   }

   @Nullable
   public static final Integer getX2() {
      return x2;
   }
}

字节码

BIPUSH 10
 PUTSTATIC com/example/kotlindemo/anyclassdemo/TestIntDemoKt.x1 : I
 BIPUSH 12
 INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;

 

观察上面代码可以发现,Koltin中的Int在JVM中实际以int存储(对应字节码类型是I)

所以:

Kotlin中Int类型等同于int。

Kotlin中Int?等同于Integer。

 

“新“的数组类型

Kotlin中数组的创建:

val funList0 = arrayOf<Int>()//长度为0的数组
val funList= arrayOf(1,2,3) //初始化长度为3的数组

Kotlin中Array并不是一个原生的数据结构,而是一种Array类,甚至可以将Kotlin中Array视作集合类的一部分。

由于Smart Casts,编译器能够隐式推断出 funList元素类型。

 

在Kotlin中,还有一些实用的类,IntArray、CharArray、ShortArray等,分别对应Java中的int[]、char[]、short[]等。

val intArray = intArrayOf(1,2)

IntArray等并不是Array的子类,所以两者创建的相同值的对象,并不是相同对象。

由于Kotlin中对原始类有特殊的优化(主要体现在避免自动装箱带来的开销),所以建议优先使用原始类型数组。

 

参考Kotlin核心编程

 

 

 

 

 

 

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值