>>> "Hello,World"+1
Hello,World1
>>> 1+"Hello,World"
error: none of the following functions can be called with the arguments supplied:
public final operator fun plus(other: Byte): Int defined in kotlin.Int
public final operator fun plus(other: Double): Double defined in kotlin.Int
public final operator fun plus(other: Float): Float defined in kotlin.Int
public final operator fun plus(other: Int): Int defined in kotlin.Int
public final operator fun plus(other: Long): Long defined in kotlin.Int
public final operator fun plus(other: Short): Int defined in kotlin.Int
1+"Hello,World"
静态类型检查可提供有用的信息给编译器。编译器可以使用更有效率的机器指令,实现编译器优化。
类型本质上是对较低层次的逻辑单元进行高层次的逻辑抽象。这样我们就可以直接使用类型在较高层次的方式思考,而不是繁重的低层次实现。
例如,我们可以将字符串想成一个值,以此取代仅仅是字节的数组。字符串就是一个抽象数据类型。
从01到类型,从类型到接口API,再到软件服务,都可以看做是广义的“类型”范畴。
程序中的变量在程序执行期间,可能会有不同的取值范围,我们可以把变量可取值的最大范围称为这个变量的类型。例如,具有类型Boolean的变量x,在程序执行期间,只能取布尔值。指定变量类型的程序设计语言,称为类型化的语言(typed language)。
如果一个语言,不限制变量的取值,称为无类型语言(untyped language),我们既可以说它不具有类型,也可以说它具有一个通用类型,这个类型的取值范围是程序中所有可能的值。
类型系统是类型化语言的一个组成部分,它用来计算和跟踪程序中所有表达式的类型,从而判断某段程序是否表现良好(well behaved)。
如果程序语言的语法中含有类型标记,就称该语言是显式类型化的(explicitly typed),否则就称为隐式类型化的(implicitly typed)。
像C、C++、Java等语言,都是显式类型化的。而像ML、Haskell、Groovy等可以省略类型声明,它们的类型系统会自动推断出程序的类型。
4.2 编译时类型与运行时类型
Koltin是一门强类型的、静态类型、支持隐式类型的显式类型语言。
4.2.1 弱类型(Weakly checked language)与强类型(Strongly checked language)
类型系统最主要的作用是,通过检查类型的运算和转换过程,来减少类型错误的发生。如果一个语言的编译器引入越多的类型检查的限制,就可以称这个语言的类型检查越强,反之越弱。根据类型检查的强弱,我们把编程语言分为
弱类型语言在运行时会隐式做数据类型转换。
强类型语言在运行时会确保不会发生未经明确转换(显式调用)的类型转换。
但是另一方面,强和弱只是相对的。
Kotlin是强类型语言。
4.2.2 静态类型(Statically checked language)与动态类型(Dynamically
checked language)
类型检查可发生在编译时期(静态检查)或运行时期(动态检查)。这样我们将编程语言分为
静态类型检查是基于编译器来分析源码本身来确保类型安全。静态类型检查能让很多bug在编码早期被捕捉到,并且它也能优化运行。因为如果编译器在编译时已经证明程序是类型安全的,就不用在运行时进行动态的类型检查,编译过后的代码会更优化,运行更快。
动态类型语言是在运行时期进行类型标记的检查,因为变量所约束的值,可经由运行路径获得不同的标记。关于动态类型,有个很形象的说法:
当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。——詹姆斯·惠特科姆·莱利(James Whitcomb Riley,1849-1916)
Kotlin是静态类型语言。
4.2.3 显式类型(Explicitly typed language)与隐式类型(Implicitly typed language)
还有一种区分方法是,根据变量名是否需要显式给出类型的声明,来将语言分为
前者需要在定义变量时显式给出变量的类型,而后者可以使用类型推论来确定变量的类型。
大多数静态类型语言,例如 Java、C/C++ 都是显式类型语言。但是有些则不是,如 Haskell、ML 等,它们可以基于变量的操作来推断其类型;
Scala 是静态类型语言,它使用类型推断功能来支持隐式类型。
Kotlin 跟Scala类似,它也使用类型推断支持隐式类型。但是,在一些场景下也需要显式声明变量的类型,所以我们可以说,同时也是显式类型。
4.3 根类型Any
Kotlin 中所有类都有一个共同的超类 Any ,如果类声明时没有指定超类,则默认为 Any 。我们来看一段代码:
>>> val any = Any()
java.lang.Object@2e377400
>>> any::class
class kotlin.Any
>>> any::class.java
class java.lang.Object
也就是说,Any在运行时,其类型自动映射成java.lang.Object
。我们知道,在Java中Object类是所有引用类型的父类。但是不包括基本类型:byte
int
long
等,基本类型对应的包装类是引用类型,其父类是Object。而在Kotlin中,直接统一——所有类型都是引用类型,统一继承父类Any
。
Any是Java的等价Object类。但是跟Java不同的是,Kotlin中语言内部的类型和用户定义类型之间,并没有像Java那样划清界限。它们是同一类型层次结构的一部分。
Any 只有 equals() 、 hashCode() 和 toString() 三个方法。其源码是
public open class Any {
* Indicates whether some other object is "equal to" this one. Implementations must fulfil the following
* requirements:
* * Reflexive: for any non-null reference value x, x.equals(x) should return true.
* * Symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
* * Transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true
* * Consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
* Note that the `==` operator in Kotlin code is translated into a call to [equals] when objects on both sides of the
* operator are not null.
public open operator fun equals(other: Any?): Boolean
* Returns a hash code value for the object. The general contract of hashCode is:
* * Whenever it is invoked on the same object more than once, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified.
* * If two objects are equal according to the equals() method, then calling the hashCode method on each of the two objects must produce the same integer result.
public open fun hashCode(): Int
* Returns a string representation of the object.
public open fun toString(): String
4.3.1 对象相等性
从Any的源码注释中,我们可以看到,判断两个对象是否相等,需要满足以下条件:
- 自反性:对于任何非空引用值x,x.equals(x) 应返回true。
- 对称性:对于任何非空引用值x和y,x.equals(y) 应返回true当且仅当y.equals(x) 返回true。
- 传递性:对于任何非空引用值x,y,z,如果x.equals(y) 返回true,y.equals(z) 返回true,那么x.equals(z) 应返回true
- 一致性:对于任何非空引用值x和y,多次调用x.equals(y) 始终返回true或者始终返回false。
另外,在Kotlin中,操作符==
会被编译器翻译成调用equals()
函数。
4.4 基本类型(Primitive Types)
本节我们来探讨学习:Kotlin的基础类型:数字、字符、布尔和数组等。
我们知道Java的类型分成两种:一种是基本类型,一种是引用类型。它们的本质区别是:
基本类型是在堆栈处分配空间存“值”,而引用类型是在堆里面分配空间存“值”。
Java的基本类型有: byte、int、short、long、float、double、char、boolean,这些类都有对应的装箱类(引用类型)。
另外,void也可以算是一种特殊的基本类型,它也有一个装箱类Void
(跟我们后文讲到的Unit、Nothing相关)。因为,Void是不能new出来的,也就是不能在堆里面分配空间存对应的值。所以,Void是一开始在堆栈处分配好空间。所以,将Void归成基本类型。
在Kotlin中,一切皆是对象。所有类型都是引用类型。没有类似Java中的基本类型。但是,可以把Kotlin中对应的这几种基本数据类型,理解为Java的基本类型的装箱类。
Integer.java
public final class Integer extends Number implements Comparable<Integer> {
* A constant holding the minimum value an {@code int} can
* have, -2<sup>31</sup>.
@Native public static final int MIN_VALUE = 0x80000000;
* A constant holding the maximum value an {@code int} can
* have, 2<sup>31</sup>-1.
@Native public static final int MAX_VALUE = 0x7fffffff;
* The {@code Class} instance representing the primitive type
* {@code int}.
* @since JDK1.1
@SuppressWarnings("unchecked")
public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
Kotlin中的Int
类型:
public class Int private constructor() : Number(), Comparable<Int> {
companion object {
* A constant holding the minimum value an instance of Int can have.
public const val MIN_VALUE: Int = -2147483648
* A constant holding the maximum value an instance of Int can have.
public const val MAX_VALUE: Int = 2147483647
我们通过Java的Integer封装类,跟Kotlin的Int类的定义可以看出两者的思想上的同源性。
Kotlin的基本类型的类图结构如下图所示
4.4.1 数字(Number)类型
Kotlin 提供了如下的内置类型来表示数字(与 Java 很相近):
类型 | 宽度(Bit) |
---|
Double | 64 |
Float | 32 |
Long | 64 |
Int | 32 |
Short | 16 |
Byte | 8 |
从上面的Kotlin的基本类型的类的结构图,我们可以看出这些内置的数据类型,都继承了Number
和 Comparable
类。例如,Byte
类型的声明:
public class Byte private constructor() : Number(), Comparable<Byte>