一点一滴学习Kotlin之数据类型

2018-12-10  本文已影响0人  付凯强
Kotlin.jpg

0. 序言

1. Boolean

val aBoolean:Boolean = true // aBoolean 变量的名称 Boolean 变量的类型 true 变量的值
val anotherBoolean:Boolean = false

fun main(args: Array<String>) {
    println(aBoolean)
    println(anotherBoolean)
}

说明:在java中有boolean和装箱类型Boolean,而Kotlin中只有Boolean,装箱的操作Kotlin会帮忙处理。

2. Number类型

包括Int、Long、Float、Double

val aBoolean:Boolean = true // aBoolean 变量的名称 Boolean 变量的类型 true 变量的值
val anotherBoolean:Boolean = false

val aInt:Int = 8
val anotherInt:Int = 0XFF
val moreInt:Int = 0b00000011
val maxInt:Int = Int.MAX_VALUE
val minInt:Int = Int.MIN_VALUE

val aLong:Long = 12324567899545
val anotherLong:Long = 123
val maxLong:Long = Long.MAX_VALUE
val minLong:Long = Long.MIN_VALUE

val aFloat:Float = 2.0F
val anotherFloat = 1E3F
val maxFloat:Float = Float.MAX_VALUE
val minFloat = - Float.MAX_VALUE

val aDouble:Double = 2.0
val anotherDouble:Double = 3.1415926
val maxDouble:Double = Double.MAX_VALUE
val minDouble:Double  =  Double.MIN_VALUE

fun main(args: Array<String>) {
    println(aBoolean)
    println(anotherBoolean)

    println(aInt)
    println(anotherInt)
    println(moreInt)
    println(maxInt)
    println(minInt)

    println(aLong)
    println(anotherLong)
    println(maxLong)
    println(minLong)

    println(aFloat)
    println(anotherFloat)
    println(maxFloat)
    println(minFloat)

    println(0.0F/0.0F)
}

true
false
8
255
3
2147483647
-2147483648
12324567899545
123
9223372036854775807
-9223372036854775808
2.0
1000.0
3.4028235E38
-3.4028235E38
NaN

说明:NaN指不是数的数,和谁相比都是false,因为没有意义

3. 拆箱、装箱

val i:Int = 1
val list:List<Int> = listOf(1,2,3)
1
[1, 2, 3]

说明:Kotlin实际上是做了拆装箱的封装,对于变量、属性、参数和返回类型——Kotlin的Int类型会被编译程Java基本数据类型Int;对于用作泛型类型参数的基本数据类型会被编译成对应的Java包装类型

fun showProgress(progress:Int){
    val percent =progress.coerceIn(0,100)
    println("We are ${percent}% done!")
}
showProgress(150)
We are 100% done!
① 整数类型:Byte、Short、Int、Long
② 浮点数类型:Float、Double
③ 字符类型:Char
④ 布尔类型:Boolean

4. 字符串

val string:String = "HelloWorld"
val fromChars:String = String(charArrayOf('H','e','l','l','o','W','o','r','l','d'))

println(string == fromChars)
println(string === fromChars)

true
false

说明:两个等号"==",在Kotlin中比较的是值。而三个等号"==="比较的是地址值。

val arg1:Int = 0
val arg2:Int = 1
println("$arg1 +$arg2 = ${arg1 +arg2}")

说明;用符号来引入变量,用{}来引入表达式。

val sayHello = "Hello \"MAOZHUXI\""
Hello "MAOZHUXI"
val rawString:String = """
        \t
        \n
"""
    \t
    \n
    println(sayHello.length)
    16

5. 转换

val A = 1
val B:Long = A

说明:这里IDE会告知错误。所以必须显示转换

val A = 1
val B:Long = A.toLong()

说明:Kotlin为每一种基本数据类型(Boolean除外)都定义有转换函数:toByte()、toShort()、toChar()等,并且支持双向转换,即Long.toInt()或Int.toLong().

① 用特殊的语法来显示地标记常量的类型,比如42L或者42.0f。
② 及时没有用以上特殊语法,当你使用数字字面值去初始化一个类型已知的变量时:

val b:Byte = 1

③ 把字面值作为实参传给函数时,必要的转换会自动地发生:

fun foo(l:Long) = println(l)
foo(42)

42

④ 算术运算符被重载了,可以接收所有适当的数字类型:

val b:Byte = 1
val l = b +1L
println(l)

2

6. 类和对象

class Man constructor(var name: String, var age: Int){

}

说明:只有一个构造方法的话,constructor也是可以省略的

class Man (var name: String, var age: Int){

}

说明:如果类中没有内容,大括号也是可以省略的

class Man (var name: String, var age: Int)
val mPerson:Man = Man("fukq",28)

说明:当然这里我们可以省略第一个Person类型:

val mPerson = Man("fukq",28)
class Man (var name: String, var age: Int){
    init {
        println("my name is $name ,my age is $age")
    }
}
my name is fukq ,my age is 28

① 首先定义一个父类

class People(var name:String,var age: Int)

② 让子类继承父类:借助符号":"

class Man (var name: String, var age: Int):People(name,age){
    init {
        println("my name is $name ,my age is $age")
    }
}

说明:用":"继承父类,并把父类的构造方法写出来,并且子类构造方法中的参数类型要省略,因为已经在父类中存在了对应的参数:

class Man(name: String, age: Int) : People(name, age) {
    init {
        println("my name is $name ,my age is $age")
    }
}

说明:除此之外,类默认是final的,所以这个时候我们要声明父类为open:

open class People(var name:String, var age: Int)
open class People(var name: String, var age: Int) {
    init {
        println("new 了一个${this.javaClass.simpleName}, my name is $name ,my age is $age")
    }
}
var answer:Any = 42

④ Any类型是非空类型的根,所以Any类型的变量不可以持有null值。如果需要持有任何可能值的变量,包括null,必须使用Any?类型。

var answer:Any? = null

说明:如果你不添加?IDE会提示报错
⑤ 在底层:Any类型对应java.lang.Object,Kotlin把Java方法参数和返回类型中用到的Object类型都看做Any类型,所以当Kotlin使用Any类型的时候,它会编译成Java字节码中的Object。
⑥ 所有Kotlin类都包含三个方法:toString、equals和hashCode:这些方法都继承自Any,Any并不能使用其他java.lang.Object的方法(比如wait和notify),但是可以通过手动把值转换程java.lang.Object来调用这些方法。因为Any定义了这三个方法:

public open class Any {

    public open operator fun equals(other: Any?): Boolean

    public open fun hashCode(): Int

    public open fun toString(): String
}

7. 空类型

public class Test_Java {
    public  static void main(String[] args){
        System.out.println(getName().length());
    }

    private static String getName(){
        return null;
    }
}

说明:Java中当你调用可能是null的值的方法或者属性的时候,容易因为值是null而报运行时异常:空指针。如何防止呢:

public class Test_Java {
    public  static void main(String[] args){
        String name = getName();
        if (name == null){
            System.out.println("name不能为空");
        }else {
            System.out.println(getName().length());
        }
    }

    private static String getName(){
        return null;
    }
}

说明:Java中你是可以随意的return内容,包括null。

fun getName():String{
    return null
}

说明:当你在方法中返回一个null值的时候编译器会报错,所以在Kotlin中不能随意return内容,与Java不同。

fun getName():String{
    return "fukq"
}
println(getName().length)

说明:在编译期就防止了如空指针这样的运行时异常,让程序更加安全,不会因运行时异常崩溃。

① 运用"?"符号来指明这个字符串,即方法返回的结果可以是null

fun getName():String?{
    return null
}

② 当方法返回可能是null的时候,我们就要对返回的数据做处理,不然编译会报错:

 val name = getName()
    if (name ==null){
        println("name不能为空")
    }else{
        println(name.length)
    }

说明:进行了空和非空的判断,程序编译无报错,但是Kotlin提供了更简洁的写法:

println(name?.length)

说明:利用安全调用运算符"?.",它允许你把一次null的检查和一次方法调用合并成一个操作。编译期不会报错,它的意思是非空的时候调用方法length,空的时候打印null,不会报空指针异常。很安全,就算给方法返回null,程序也不会crash。
③ 当方法返回是null的时候,执行return或者其他

    val name = getName()
    if (name ==null) return
    println(name.length)

说明:以上是常规写法;Kotlin有方便的Elvis运算符"?:"来处理这种情况

    val name = getName() ?: return
    println(name.length)
    val name = getName() ?: ""
    println(name.length)

④ 当你确认可空类型不为null的时候,可使用非空断言“!!"符号:

fun hello(s:String?){
    val sNotNUll:String = s!!
    println(sNotNUll.length)
}

说明:示例中的s是一个可空类型,但是你确信你传进来的是非空类型,这时候可以使用非空断言"!!"告诉编译器不用检查是否是null。另外你要注意的是假如你判断错误,运行时会抛出空指针异常NullPointerException。所以非空断言告诉编译器:"我知道这个值不为null,如果我错了我准备好了接收这个异常“。

8. 类型转换安全

public class Parent {
}

② 定义Child类:

public class Child extends Parent {

    public String getName(){
        return "fukq";
    }
}

③ 定义类型转换测试类TypeCast:

public class TypeCast {
    public static void main(String[] args){
        Parent parent = new Child();
        ((Child) parent).getName();

        if (parent instanceof Child){
            ((Child) parent).getName();
        }
    }
}

说明:你会发现已经判断parent是Child实例了,但是后面的代码还是要强转才行。

    val parent:Parent = Child()
    if (parent is Child){
        println(parent.name)
    }

说明:你会发现Kotlin是智能转换,不用强转。

    val parent = Parent()
    val child:Child = parent as Child
    println(child.name)
Exception in thread "main" java.lang.ClassCastException: Parent cannot be cast to Child
    at Test_Kotlin_01Kt.main(Test_Kotlin_01.kt:135)

说明:那我强转失败,不想转换抛出异常:

    val parent = Parent()
    val child:Child? = parent as? Child
    println(child)
null

说明:这个时候我们收到的就是null,而不是异常。

9. 包

这里讲解包主要讲解如何给包指定其他名称,即修改包的命名空间

class XiaoMing(var age:Int){

}
package TianJin

fun main(args: Array<String>) {
    val xiaoming_tj:XiaoMing = XiaoMing(50)
    val xiaoming_bj:Beijing.XiaoMing = Beijing.XiaoMing(60)
}

说明:会发现在Tianjin的包里面,Beijing的XiaoMing要展示全路径代码,因为示例的包结构层次不是很深,实践中的包结构层次如果深,那Beijing的XiaoMing显示全路径的话,代码会变得很长,所以这里我们利用“as"修改它的命名空间:

package TianJin

import Beijing.XiaoMing as BJ_XiaoMing

fun main(args: Array<String>) {
    val xiaoming_tj:XiaoMing = XiaoMing(50)
    val xiaoming_bj:BJ_XiaoMing =BJ_XiaoMing(60)
}

10. 区间

    val range:IntRange = 0..1024 // 闭区间 [0,1024]
val range_exclusive:IntRange = 0 until 1024 //右开区间[0,1024)

说明:IntRange继承的是ClosedRange

public class IntRange(start: Int, endInclusive: Int) : 
IntProgression(start, endInclusive, 1), ClosedRange<Int> {...}

说明:ClosedRange接口中有两个方法

public interface ClosedRange<T: Comparable<T>> {
    public val start: T
    public val endInclusive: T
    public operator fun contains(value: T): Boolean = value >= start && value <= endInclusive
    public fun isEmpty(): Boolean = start > endInclusive
}

说明:
① contains运用:

  val range:IntRange = 0..1024 // 闭区间 [0,1024]
 println(range.contains(50)) 
 true

② isEmpty()运用

val emptyRange:IntRange = 0..-1
println(emptyRange.isEmpty())
true

③ contains返回一个operator,这个operator对应的运算符号是"in"

    println(range.contains(50))
    println(50 in range)

说明:以上两句话是等价的。

    for (i in range){
        println("$i ")
    }

11. 数组

    val arrayOfInt:IntArray = intArrayOf(1,3,5,7)
    val arrayOfChar:CharArray = charArrayOf('H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd')

说明:为了避免拆箱装箱带来的性能开销,特设数组定制版

    val arrayOfString:Array<String> = arrayOf("I","am","fukq")
    val arrayOfPerson:Array<Child> = arrayOf(Child(),Child(),Child())
println(arrayOfInt.size) //长度
for(i in arrayOfInt){
        println("$i ")
    }
println(arrayOfPerson[1])

说明:这样打印出来的内存地址值,想打印字段都信息,可以在类中复写toString方法

class XiaoMing(var age:Int){

    override fun toString(): String {
        return "XiaoMing的年龄是$age"
    }
}
val arrayOfPerson:Array<XiaoMing> = arrayOf(XiaoMing(50),XiaoMing(60),XiaoMing(70))
XiaoMing的年龄是60
arrayOfPerson[1] = XiaoMing(100)
rrayOfChar.joinToString()
H, e, l, l, o, W, o, r, l, d

说明:看下源码

public fun CharArray.joinToString(separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((Char) -> CharSequence)? = null): String {
    return joinTo(StringBuilder(), separator, prefix, postfix, limit, truncated, transform).toString()
}

说明:其实是一个StringBuilder拼接,默认分隔符是", ",改为空

println(arrayOfChar.joinToString(""))
println(arrayOfInt.slice(1..2))
[3, 5]

12. 后续

如果大家喜欢这篇文章,欢迎点赞!
如果想看更多 Kotlin 方面的技术,欢迎关注!

上一篇下一篇

猜你喜欢

热点阅读