LotLin六种特殊类

嵌套类

一个类可以在单独的代码文件中定义,也可以在另一个类内部定义,后一种情况叫做嵌套类,意即A类嵌套在B类之中。乍看过去,这个嵌套类的定义似乎与Java的嵌套类是一样的,但其实有所差别。Java的嵌套类允许访问外部类的成员,而Kotlin的嵌套类不允许访问外部类的成员。倘若Kotlin的嵌套类内部强行访问外部类的成员,则编译器会报错“Unresolved reference: ***”,意思是找不到这个东西。下面是Kotlin定义嵌套类的代码例子:

fun test(){   
 val flower = Tree.Flower("荷花")   
  flower.getName()    
  Tree("向日葵").
  Fruit("apple")}
  class Tree(var treeName:String){   
   class Flower(var flowerName:String){   
    fun getName():String{     
       return "荷花"    }  
         } 
        inner class Fruit(var name:String){
    }
    }

内部Kotlin限制了嵌套类不能访问外部类的成员,针对该问题,Kotlin另外增加了关键字inner表示内部,把inner加在嵌套类的class前面,于是嵌套类华丽丽转变为了内部类,这个内部类比起嵌套类的好处,便是能够访问外部类的成员。所以,Kotlin的内部类就相当于Java的嵌套类,而Kotlin的嵌套类则是加了访问限制的内部类。按照前面演示嵌套类的树木类Tree,也给它补充内部类的定义,代码:

class Tree(var treeName:String){
   class Flower(var flowerName:String){
      fun getName():String{
          return "荷花"
      }
      }
         inner class Fruit(var name:String){
       }
}
调用内部类时,要先实例化外部类,再通过外部类的实例调用内部类的构造函数,也就是把内部类作为外部类的一个成员对象来使用,这与成员属性、成员方法的调用方法类似。内部类的调用代码如下所示:
```j
btn_class_inner.setOnClickListener {
         //使用内部类时,必须调用外部类的构造函数,否则编译器会报错
      val peach = Tree("桃树").Fruit("桃花");
      tv_class_secret.text = peach.getName()
}

枚举类

Java有一种枚举类型,它采用关键字enum来表达,其内部定义了一系列名称,通过有意义的名字比0/1/2这些数字能更有效地表达语义。下面是个Java定义枚举类型的代码例子

enum Season { SPRING,SUMMER,AUTUMN,WINTER }

上面的枚举类型定义代码,看起来仿佛是一种新的数据类型,特别像枚举数组。可是枚举类型实际上是一种类,开发者在代码中创建enum类型时,编译器会自动生成一个对应的类,并且该类继承自java.lang.Enum。因此,Kotlin拨乱反正,摒弃了“枚举类型”那种模糊不清的说法,转而采取“枚举类”这种正本清源的提法。具体到编码上,则将enum作为关键字class都得修饰符,使之名正言顺地成为一个类——枚举类。按此思路将前面Java的枚举类型Season改写为Kotlin的枚举类,改写后的枚举类代码如下所示:

enum class SeasonType {
SPRING,SUMMER,AUTUMN,WINTER
}

密封类

前面演示外部代码判断枚举值的时候,when语句末尾例行公事加了else分支。可是枚举类SeasonType内部一共只有四个枚举变量,when语句有四个分支就行了,最后的else分支纯粹是多此一举。出现此种情况的缘故是,when语句不晓得SeasonType只有四种枚举值,因此以防万一必须要有else分支,除非编译器认为现有的几个分支已经足够。
为解决枚举值判断的多余分支问题,Kotlin提出了“密封类”的概念,密封类就像是一种更加严格的枚举类,它内部有且仅有自身的实例对象,所以是一个有限的自身实例集合。或者说,密封类采用了嵌套类的手段,它的嵌套类全部由自身派生而来,仿佛一个家谱明明白白列出来某人有长子、次子、三子、幺子。定义密封类时使用关键字sealed标记,具体的密封类定义代码如下所示:

 sealed class SeasonSealed {
//密封类内部的每个嵌套类都必须继承该类
class Spring (var name:String) : SeasonSealed()
class Summer (var name:String) : SeasonSealed()
class Autumn (var name:String) : SeasonSealed()
class Winter (var name:String) : SeasonSealed()
}

有了密封类,通过when语句便无需指定else分支了,下面是判断密封类对象的代码例子:

btn_class_sealed.setOnClickListener {
     var season = when (count++%4) {
         0 -> SeasonSealed.Spring("春天")
         1 -> SeasonSealed.Summer("夏天")
         2 -> SeasonSealed.Autumn("秋天")
         else -> SeasonSealed.Winter("冬天")
    }
    //密封类是一种严格的枚举类,它的值是一个有限的集合。
    //密封类确保条件分支覆盖了所有的枚举类型,因此不再需要else分支。
    tv_class_secret.text = when (season) {
        is SeasonSealed.Spring -> season.name
        is SeasonSealed.Summer -> season.name
        is SeasonSealed.Autumn -> season.name
        is SeasonSealed.Winter -> season.name
    }
}

数据类

data class Plant(var name:String, var stem:String, var leaf:String, var flower:String, var fruit:String, var seed:String) {
	}

模板类

如果某个泛型函数在类内部定义,即变成了这个类的成员方法,又该如何定义它呢?这个问题在Java中是通过模板类(也叫做泛型类)来解决的,例如常见的容器类ArrayList、HashMap均是模板类,Android开发中的异步任务AsyncTask也是模板类。

//在类名后面添加“<T>”,表示这是一个模板类
class River<T> (var name:String, var length:T) {
    fun getInfo():String {
        var unit:String = when (length) {
            is String -> "米"
            //Int、Long、Float、Double都是数字类型Number
            is Number -> "m"
            else -> ""
        }
        return "${name}的长度是$length$unit。"
    }
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值