Kotlin基础 - 第二章基本数据类型和基础语法

本文详细介绍了Kotlin的基础数据类型,包括布尔型、数值型、字符型及其转换。还讲解了字符串的使用,如引用变量、格式化字符串以及获取长度的方法。此外,探讨了Kotlin中的变量定义,特别是var与val的区别,以及类、构造函数、继承、空安全和类型转换等核心概念。
摘要由CSDN通过智能技术生成

kotlin基础 - 基本数据类型和基础语法



#### [kotlin官方文档 https://www.kotlincn.net/docs/reference/](https://www.kotlincn.net/docs/reference/) ####

基本类型

1. Boolen

 	val aBoolean: Boolean = true
    val anOtherBoolean: Boolean = false
    println(aBoolean)
    println(anOtherBoolean)

运行结果:

true
false

2.数值类型

整数 (32位 2147483647 ~ -2147483648)

val anInt: Int = 0xffffff
val anOtherInt: Int = 0b00111111
val maxInt: Int = Int.MAX_VALUE
val minInt: Int = Int.MIN_VALUE

println(anInt)
println(anOtherInt)
println(maxInt)
println(minInt)

运行结果

16777215
63
2147483647
-2147483648

长整数(64位 -9223372036854775808 ~ 9223372036854775807)

val aLong: Long = 1154545454545542545
val anOtherLong: Long = 123
val minLong: Long = Long.MIN_VALUE
val maxLong: Long = Long.MAX_VALUE

println(aLong)
println(anOtherLong)
println(minLong)
println(maxLong)

运行结果

1154545454545542545
123
-9223372036854775808
9223372036854775807

单精度浮点型 (32位 -3.4028235E38 ~3.4028235E38 存在精度问题)

val aFloat:Float = 0.12F
val anOtherFloat:Float = 1E3F
val minFloat:Float = Float.MIN_VALUE
val maxFloat:Float = Float.MAX_VALUE

println(aFloat)
println(anOtherFloat)
println(minFloat)
println(maxFloat)

运行结果

0.12
1000.0
1.4E-45
3.4028235E38

双精度浮点型(64位 -1.7976931348623157E308 ~ 1.7976931348623157E308 存在精度问题)

val aDouble:Double = 0.12
val anOtheDouble:Double = 1E3
val minDouble:Double = Double.MIN_VALUE
val maxDouble:Double = Double.MAX_VALUE


println(aDouble)
println(anOtheDouble)
println(minDouble)
println(maxDouble)

运行结果

0.12
1000.0
4.9E-324
1.7976931348623157E308

短整型 (16位 -32768 ~ 32767)

val aShort:Short = 12152
val anOtheShort:Short = 120
val minShort:Short = Short.MIN_VALUE
val maxShort:Short = Short.MAX_VALUE

println(aShort)
println(anOtheShort)
println(minShort)
println(maxShort)

运行结果

12152
120
-32768
32767

字节 (8位-128 ~ 127)

val aByte:Byte = 121
val anOtheByte:Byte = -12
val minByte:Byte = Byte.MIN_VALUE
val maxByte:Byte = Byte.MAX_VALUE

println(aByte)
println(anOtheByte)
println(minByte)
println(maxByte)

运行结果

121
-12
-128
127

注意: Float.NaN 不是任何数值 不可以和任何数值比较大小和判断相等

比如

println(0 / 0.0F == Float.NaN)

运行结果为

false

在 kotlin中基本类型可以自动完成自动装箱和自动拆箱,也就是说kotlin中的Long是java中Long和long的组合体,、Int、Short、Double、Float以此类推

Char类型

  • 字符对应java中的 Character
  • 占两个字节,表示一个16位的 unicode 字符
  • 使员单引号引起来 比如 'A','0','中','\n'

kotlin中的转义字符

转义字符含义
\t制表符
\b光标后退一个字符
\n回车
\r光标回到行首
单引号
"双引号
\反斜杠
$美元符号,kotlin支持美元符号开头的字符串模板

基本类型的转换

不同于java , kotlin不支持隐式转换

举例

val age = 25
//需要对应类型变量调用自己的转换函数
val ageLong: Long = age.toLong()
println(aLong)

运行结果

25

kotlin中的字符串

示例

val aString: String = "HelloWord"
val arrayString: String = String(charArrayOf('H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'd'))


println(aString)
println(arrayString)

//kotlin使用 `==` 判断两个字符串变量的值相等
println(aString == arrayString)

//使用 `===` 判断两个字符串的地址是不是相同
println(aString === arrayString)

运行结果

HelloWord
HelloWord
true
false

注意 :

  • == 可以判断两个字符串变量内容是否相同,相当于java的 equal 方法

  • === 可以判断两个字符串变量的地址是否相同,相当于java的 == 方法

$变量, 在字符串中可以引用一个变量的值
val num1: Int = 120
val num2: Int = 160

println("$num1 + $num2 = ${num1+num2}")

运行结果

120 + 160 = 280

如果我们就是期望输出 $变量 本身,我们可以借助转义字符来实现 \$变量

println("\$num1")

运行结果

$num1
使员工 """ """ 定义带有格式的字符串

val formatStr: String = “”"
去年今日此门中,人面桃花相映红。
出自唐代崔护的《题都城南庄》

    去年今日此门中,人面桃花相映红。
    人面不知何处去,桃花依旧笑春风。
"""

println(formatStr)

运行结果

    去年今日此门中,人面桃花相映红。
    出自唐代崔护的《题都城南庄》

    去年今日此门中,人面桃花相映红。
    人面不知何处去,桃花依旧笑春风。
使用 字符串变量.length 获取字符串的长度
val formatStr: String = """
    去年今日此门中,人面桃花相映红。
    出自唐代崔护的《题都城南庄》

    去年今日此门中,人面桃花相映红。
    人面不知何处去,桃花依旧笑春风。
"""
println(formatStr.length)

运行结果

104

kotlin中变量的定义

Kotlin 中可以使用 var 与 val 定义变量
比如

//定义一个非空的变量
val name: String = "小明"
var name: String = "小明"

//定义一个可空的变量
val name: String? = null
var name: String? = null
Kotlin 中 var 与 val 定义变量的区别,及使用场景
  • 基本数据类型使用

测试代码:

var a: Int = 1
a = 2
printlin(a)

//得到结果
2

val b: Int = 1
b = 2

//运行结果
error: val cannot be reassigned
  • 引用数据类型

当对象使用 val 实例化时

val 实例化的对象,其 var 属性还可以进行更改;但是不可以对实例化的对象再赋值
var 实例化的对象没有任何限制

class Language() {
	...     
	var name: String = ""
	... 
}


var l = Language()
l.name = "Java"
printlin(l.name)
//运行正常	

l = Language()
printlin(l.name)
//运行正常



//val定义的属性,可以改变对象的内容,但是不可以改变对象的引用地址
val l2 = Language()
l2.name = "Kotlin"
l2 = Language()

//报错
error: val cannot be reassigned
val 的使用场景

举个例子,我现在定义一个 Button 对象,这个对象指向 layout 中的一个 button,这种情况下使用 val 就有实战意义了,因为这个 Button 变量理论上是不应该再指向其他 button 了,能很好的规避乱赋值的情况;而且还不影响修改 Button 的属性。

所以,原则应该是,尽量使用 val。

kotlin中的类和变量

kotlin中所有的类都是继承自 Any 类的,相当于java 中任何的类都是继承自 Object 类的,也就是说 Any 在Kotlin中是所有类的基类


类的声明
class Invoice{}
class Empty   //如果类没有实体可以省略{ }
构造函数

它跟在类名(与可选的类型参数)后,如果没有注解或可见性修饰符可以省略constructor关键字

class Person constructor(name: String) {}
class Person (name: String ){}     //这两个声明是一样的

注意这里相当于java中构造函数和类声明的合体

主构造函数不能包含任何代码块, 初始化的代码可以放到以init关键字为前缀的代码块中。

class Person (val name: String) {
	//优先于初始化块初始化
    val s  = "name $name".also(:: println)

	//创建类的同时会指定这段代码块,相当于java中的构造函数
    init {
        println("init name : $name")
    }
	//晚于初始化块初始化
    val tian = "songtao $name".also(::println)
}

注意:主构造函数中的参数可以在初始化块中使用,也可以在类体内声明的属性初始化器中使用。
在类实例化期间,初始化块和属性初始化代码按照在类中编码的顺序执行。

次构造函数

类也可以声明前缀有 constructor 的次构造函数,如果一个类中有主构造函数那么每一个次构造函数都需要
委托给主构造函数,可以直接委托也可以通过别的次构造函数委托,委托同类构造函数使用this关键字

class Person (val name: String) {
    val s  = "name $name".also(:: println)
    init {
        println("init name : $name")
    }
    val tian = "tian name: $name".also(:: println)

    constructor(name: String, age: Int): this(name) {

    }
}

创建代码

val xiaoming: Person = Person("小明")
val xiaofang: Person = Person("小芳",22)

注意:初始化块中的代码实际会作为主构造函数的一部分,委托给主构造函数实际上会作为次构造函数的第一条代码执行。因此初始化块都是执行在次构造函数之前,即使没有主构造函数这种委托也会隐式存在。
如果一个类没有任何主次构造函数,它会生成一个不带参数的主构造函数,如果你想你的类没有一个公共的主构造函数,可以用限制符声明它的非公共主构造函数

class Tian private constructor(){}
创建类的实例

kotlin中没有Java的new关键字,实例化类像普通函数一样调用构造函数

val person = Person("tian")
类成员

类的成员包括

  • 构造函数和初始化块
  • 函数
  • 属性
  • 嵌套类和内部类
  • 对象声明

继承

kotlin中所有的类都有一个共同的超类Any, 和Java中的object一致,没有超类声明的类Any就是它的默认超类,要声明一个超类,我们把类型放到类头的冒号后. kotlin力求显示清晰,与Java不同,kotlin对于公开的超类和可重写的函数都需要用时open关键字来显示指定公开,类似java中的public。

	open class Person
	class Man : Person
	open class Woman(name:String): Person()
	class Student(name:String): Woman(name)  
	class MyView: View{
	    constructor(context: Context): super(context)
	    constructor(context: Context, attrs: AttributeSet): super(context, attrs)
	}

类继承的特点

总结:

  • 提取多个类的共性得到一个更抽象的类,即父类
  • 子类拥有父类的全部特征
  • 子类可以自定义自己的特征

空类型和智能类型转换

Kotlin 类型安全(对空指针的优化处理)
  • 首先我们看下面的一段 java 代码:

      public static void main(String[] args){
          System.out.println(getName().length());
      }
      
      public static String getName(){
          return null;
      }
    
  • 如果运行 main 函数,jvm 会报 Exception in thread "main" java.lang.NullPointerException 的错误。相信大家在 codding 的时候稍有不慎就会遇到这个问题,非常让我们头疼。为了安全起见,我们要做大量的空指针判断,我们的时间严重浪费了在这些毫无技术含量的处理上。于是我们的 main 函数变成了:

       public static void main(String[] args) {
          String name = getName();
          if (null == name) {
              System.out.println("未获取到 name!");
              return;
          }
          System.out.println(name.length());
       }
    
  • 但是 Kotlin 的出现,挽救了我们处理空指针的时间。同样的我们看下面一段代码:

      fun getName(): String {
          return null // 这种情况在 Kotlin 中是不允许的
      }
    
  • 同样是返回一个 String 类型的 getName() 函数,在 Kotlin 中如果返回 null 是无法通过编译的。
    这样做,很显然避免的了出现空指针的可能性,但是问题又来了,如果 getName() 就是可以返回 null 呢?很简单,我们在返回值类型后面加一个 ? 就表示可以返回 null 了,于是代码变成了:

      fun getName(): String? {
          return null
      }
    
  • 那接着问题又来了,这样不是又跟 Java 一样了吗?同样存在空指针的危险:

      fun getName(): String? {
          return null
      }
      
      fun main(args: Array<String>) {
          println(getName().length) // 编译通不过,getName()有可能为null
      }
    
  • 由于上面的那段代码编译无法通过,于是只好进行空指针判断了

      fun getName(): String? {
          return null
      }
      
      fun main(args: Array<String>) {
          var name = getName()
          if(null==name){
              println("未获取到 name!")
              return
          }
          println(name.length)
      }
    
  • 这样一来,Kotlin 代码和 Java 就一样了,没什么优点了!不!其实上面的代码是可以简化的

      fun getName(): String? {
          return null
      }
      
      fun main(args: Array<String>) {
          println(getName()?.length) // null
      }
    
  • 上面的代码的意思就是,如果 getName() 不为空,则打印长度,否则就返回。
    如果知道一个值不可能为空,但是在定义的时候定义了有可能为空,而且也不想在判断,该怎么将解决?

      val aString: String? = "Hello Kotlin"
      println(aString.length) // 编译错误
      这个时候就可以使用强制执行,就是在变量后面加两个 !
      
      val aString: String? = "Hello Kotlin"
      println(aString!!.length) // 12
    

总结

代码表达式解释
val a:String = 变量将一个非空的变量赋值给字符串a,使用a的时候不需要考虑空指针
val a:String = 变量?将一个可空的变量赋值给字符串a,使用的时候需要考虑空指针,比如 println(a?.length)
val a:String = 变量? return将一个可空的变量赋值给字符串a,如果为空执行:后面的代码
val a:String = 变量? return println(a!!.length)[变量]!! 告诉编译器这个不可能为空,可以强制编译通过

任意类型都有可空和不可空两种

val notNull : String = null //错误,赋值不能为空
val nullable : String ?= null //正确,可以为空
notNull.length //正确,不为空的只可以直接使用
nullable.length //错误,可能为空不能直接获取长度
notNull!!.length //正确,强制认定 notNull 部为空
nullable?.length //正确,如果 nullable 为空,返回空

类型转换

对于子父类之间的类型转换

  • 先看这样一段 Java 代码

      public class Person{
      }
      
      public class Student extends Person{
          public  void study(){
              System.out.println("我在学习一门新的语言 Kotlin !");
          }
      }
      
      public static void main(String[] args){
          Person person = new Student();
          if(person instanceof Student){
      		//已经判断过类型了,但是使用的时候还是需要强转一次,不够这能呀
              ((Student) person).study();
          }
      }
    
  • 尽管在 main 函数中,对 person 这个对象进行了类型判断,但是在使用的时候还是需要强制转换成 Student 类型,这样是不是很不智能?
    同样的情况在 Kotlin 中就变得简单多了

      fun main(args: Array<String>) {
          val person: Person = Student()
      	
          if (person is Student) {
      		//kotlin可以根据程序的上下文自动推测数据类型,这一点还是相当人性化的
              person.study()
          }
      }
    

注意:kotlin 中的 is 可以判断一个对象是这个类型,姓党与java的 instanceof

  • 在 Kotlin 中,只要对类型进行了判断,就可以直接通过父类的对象去调用子类的函数了
安全的类型转换
  • 还是上面的那个例子,如果我们没有进行类型判断,并且直接进行强转,会怎么样呢?

      public static void main(String[] args) {
          Person person = new Person();
          ((Student) person).study();
      }
    

结果就只能是 Exception in thread "main" java.lang.ClassCastException

  • 那么在 Kotlin 中是不是会有更好的解决方法呢?

      val person: Person = Person()
      //as可以将一个类对象转换成对应的类型,如果转换失败抛出转换失败的异常,加上? 可以避免转换异常
      val student:Student? =person as? Student
      println(student) // null
    

在转换操作符后面添加一个 ?,就不会把程序 crash 掉了,当转化失败的时候,就会返回一个 null,当然后?的后面可以跟上任意的表达式,比如return

在空类型中的智能转换
  • 需要提前了解 Kotlin 类型安全的相关知识(Kotlin 中的类型安全(对空指针的优化处理))

      val aString: String? = "Hello Kotlin"
      if (aString is String) {
          println(aString.length)
      }
    

aString 在定义的时候定义成了有可能为 null,按照之前的写法,我们需要这样写

	val aString: String? = "Hello Kotlin"
	println(aString?.length)

但是已经进行了是否为 String 类型的判断,所以就一定 不是 空类型了,也就可以直接输出它的长度了

总结

  • java样式的类型转换(不安全 转换失败抛出异常)

      val sub : subClass = parent as subClass
    
  • 安全的类型转换(转阿混失败返回null)

      val sub : subClass? = parent as? subClass
    
  • 智能类型转换

如果前面的代码判断出了变量的类型,后面的代码不需要转换,可以直接使用

  	val child: Parent = Child()

	if (child is Child)
    println(child?.getName())
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值