kotlin封装

kotlin类型兼容java类型的全部语义和概念,但是也并非完全相同,不过在kotlin中,一个类型于java中的一样,也包含如下元素:

  • 构造器和初始化模块
  • 成员函数
  • 属性
  • 内部类
  • 对象声明

构造函数

构造函数其实并不是一个真正的函数,因为它没有返回值类型,连函数名也被严格约束。而从编译器的角度看,构造函数的确不是函数,因为编译器通常会对构造函数进行特别处理,在C++中,构造函数会被处理成内存分配指令,在java中,会被处理成new指令。因此构造函数可以被看着一个语法糖层面的伪函数。

  • 构造函数声明
//直接在类型名称后面紧跟参数列表,完成的构造函数定义,叫主构造函数
//只需要一行就实现了属性定义和构造函数的声明,比java简洁太多
//显示的声明了有参主构造函数,就会覆盖默认的无参构造函数
class SharedBike (var name:String,var color:Int) {
    //kotlin 将init块,添加进了 构造函数中的
    init {
        println("在构造函数中,进行一点别的逻辑功能")
    }
     var price:Int = 0
    //二级构造函数 必须 间接或者直接代理 主构造函数 this(), 其实这也正是kotlin源程序中以 .kt 结尾的类型声明要添加括号的原因
    constructor(name: String,color: Int,price:Int):this(name,color){
        this.price = price
    }
}

fun main() {
    val sharedBike = SharedBike("哈罗",0xff0000)
    println(sharedBike.name)
    println(sharedBike.color)
}
  • 构造函数的权限声明
class SharedBike private constructor(var name: String, var color: Int) {
    var price: Int = 0

    //次级构造函数声明访问权限,直接在constructor关键字前添加就可以了
    public constructor(name: String, color: Int, price: Int) : this(name, color) {
        this.price = price
    }
}

fun main() {
    //主构造函数被声明为私有,就只能调用次级构造函数了 ,主构造函数声明访问权限,必须添加关键字 constructor
    val sharedBike = SharedBike("哈罗", 0xff0000, 256)
    println(sharedBike.name)
    println(sharedBike.color)
}
  • 初始化顺序
class Animal() {
    //声明时初始化
    var name:String = getName()
    constructor(name:String):this(){
        println("构造函数时初始化")
        this.name = name
    }
    init {
        name = "name_from_init"
        println("init 块中初始化")
    }

    fun printName(){
        println("name = $name")
    }
}

fun getName():String{
    println("声明时初始化。。。")
    return "name_from_declare"
}

fun main() {
    val animal = Animal("name_from_constructor")
    animal.printName()
}

结果:

声明时初始化。。。
init 块中初始化
构造函数时初始化
name = name_from_constructor

事实上之所以是这样一个顺序,于JVM虚拟机实例化对象的总体策略有关,当JVM实例化Animal时,会依次执行如下逻辑:
1 在路径下找到 Animal.class
2 在JVM的heap内存域(即堆区)为Animal实例分配足够的内存空间。
3 将Animal实例内存空间清零,将其实例对象内的各个基本类型的字段都设置为对应的默认值。
4 如果字段在声明时进行了初始化,则按顺序执行各个字段的初始化逻辑
5 如果定义init{}块,则执行init{}块中的逻辑
6 如果定义了构造函数,则执行构造函数中的逻辑

属性

属性String 和String? 是不同的,所以 属性String的值不能赋值给 String?

class Animal() {
    //声明属性 直接赋值
    var name = "张三"
    //声明一个可以为空的属性, 添加了 ? 表示这个属性可以为null,否则属性不能为空值
    var height:Int? = null
    //强制 设置一个属性为空 , 会报错
//    var weight :String = null!!
    //声明一个abstract的属性,可以不用赋值,但是对应的其所在的类 必须也是 abstract 修饰的
    // abstract var hobby:String
}
  • 属性的空安全
class Animal {
    var name:String?= null
    fun test(){
       name?.let {
           println(it)
       }
        println(name?.length)
    }
}

fun main() {
    val animal = Animal()
    animal.test()
    animal.name = "小白兔"
    println("-----------赋值后------------------")
    animal.test()
}

结果:

null 可控属性不加let块 执行为空,加了let块 与if 判断一样
-----------赋值后------------------
小白兔
3

访问权限

kotlin 中顶级变量和类属性默认情况下的访问权限都是public。这一点与java完全不同,java中默认情况下都是private。

class Animal {
    var name:String = "二哈"
        private set //设置赋值方法为private
}

fun main() {
    val animal = Animal()
    //赋值报错
    animal.name = "sldfk"
}

数组

kotlin 的大部分语法特性都是基于java的,编写习惯也没有太大变化,而数组是个例外。

数组的初始化

  • 通过Array接口声明数组
//声明一个 大小为3,初始值都是0的数组 ,"it->"可以省略
var asc = Array(3,{it -> 0})
  // 如果不想kotlin自动推断类型,可以在声明数组的时候显示标记
var asc:Array<Int> = Array(3) { 0}
// array 也可以根据步长来 初始化值
var asc:Array<Int> = Array(3) { it * 2}
  • 数组读写
 val asc:Array<Int> = Array(3) { it * 2}
    //写数组
    asc[0] = 12
    asc.set(1,24)
    //读数组
    val a = asc[0]
    val b = asc.get(1)
  • 声明一个引用类型数组
class Animal(val name:String,age:Int) {
    var age:Int = age
    override fun toString(): String {
        return "dog name = $name, age = $age,height = ${age * 2}"
    }
}

fun main() {
    val asc = Array(3) { Animal(it.toString(),it + 1)}
    for (a in asc){
        println(a.toString())
    }
    /**
     * dog name = 0, age = 1,height = 2
    dog name = 1, age = 2,height = 4
    dog name = 2, age = 3,height = 6
     */
}
  • 其他声明数组的方式
fun main() {
    //声明一个Animal 类型的大小为5的数组,但是没有对数组元素进行初始化,元素都为null
    val asc = arrayOfNulls<Animal>(5)
    //声明一个Int类型的数组,大小为3,默认初始值为0,其他基本类型也可以使用类似的方法进行初始化
    val arr = IntArray(3)
    for (i in asc) println(i)
    //声明java中的包装类型,(作参数传入需要包装类型的java方法中时,会自动装箱)
    val array = arrayOfNulls<Int>(2)
    array[0] = 12
    array[1] = 2
}
  • 多维数组
 //声明一个二维数组,如下声明了一个2行三列的数组
    val asc = Array(2){Array(3){0} }
    //遍历多维数组
    for (i in asc.indices){
        for (j in asc[i].indices){
            println("i = $i,j = $j")
        }
    }
    //读写多维数组
    asc[0][2] = 12
    val asc02 = asc[0][2]
    println(asc02)
    //声明一个引用类型的多维数组
    val an = Array(3){ arrayOfNulls<Animal>(3) }
  • 数组与列表转换
    在实际开发中列表的使用大于数组,因为列表的长度可以动态改变,数组不行。
val asc = IntArray(3)
    asc[0] = 12
    asc[1] = 16
    asc[2] = 19
    val array2list = asc.asList() 
    for (e in array2list){
        println(e)
    }

    //声明一个列表
    val list = ArrayList<Int>(2)
    list.add(1)
    list.add(2)
    list.add(3)
    for (e in list){
        println(e)
    }
    //将列表转成数组
    val ints =  list.toArray()
    for (i in ints.indices) println(i)

静态函数和伴随对象

kotlin中的类不像java中的类,没有静态方法和静态变量,在kotlin类中编写的函数和属性,必须通过类实例对象才能访问,而不能直接通过类名访问。kotlin 特别设计了"伴随对象"。伴随对象顾名思义是一个对象声明,要定义一个伴随对象很简单,通过 companion object 关键字定义,实例如下:

class Animal() {
    var name:String? = null
    //声明一个伴随对象 InnerAnimal,并在其中定义函数run(),
    // 从外面可以直接通过Animal类型先到名 作为前缀调用该伴随对象的方法
    companion object InnerAnimal{
        fun run(){
            println("fun run running .......")
        }
    }
  //一个类中 只能定义一个伴随对象
  //伴随对象的名称可以省略,比如这里的 InnerAnimal 可以不写
//    companion object {
//        fun run(){
//            println("fun run running .......")
//        }
//    }
}

fun main() {
    Animal.run()
}
  • 伴随对象 因为是一个对象声明,所以不能实例化
  • 伴随对象中的属性
    在伴随对象中,不仅可以声明方法,也可以定义变量。所定义的变量也可以通过伴随对象的宿主类直接访问,看起来就像java类中的静态变量一样
class Animal() {
    var name:String? = null
    companion object InnerAnimal{
        var speed = 20
        fun run(){
            println("fun run running speed = $speed")
        }
    }
}

fun main() {
    Animal.run()
    Animal.speed = 50
    Animal.run()
}
  • 伴随对象的初始化
    伴随对象没有构造函数,但是可以给伴随对象添加 init{} 块,init块绘制实例化伴随对象所在类,或者第一次调用伴随对象的时候执行。
  • 伴随对象的原理
    以上面的Animal类为例子,经过编译器编译之后,speed变量就变成了 Animal类中的静态变量,伴随对象InnerAnimal 也是Animal类中的一个静态变量了。kotlin中所谓的伴随对象,其实就是一个普通的变量,但是这个变量有其不普通之处,那就是其变量名与伴随对象名称完全相同,看起来像一个类名,同样,InnerAnimal变量的访问限定符包括static,因此可以 Animal.InnerAnimal 这样访问伴随对象
  • 匿名类
open class Animal(val name:String) {
    open fun run(){
        println("$name run........")
    }
}

fun main() {
    val a = object {
        init {
            println("init ..........")
        }
        //不像java中匿名类,只能调用父类(实现接口)的方法
        //可以直接在 匿名类中 声明方法
        fun print() {
            println("a.print()......")
        }
    }
    a.print()

    //匿名类 也可以实现接口 或者 继承某个基类
    val dog = object :Animal("二哈"){
        override fun run(){
            println("dog $name is running ...")
        }
    }

    dog.run()
}

init ..........
a.print()......
dog 二哈 is running ...

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,542评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,822评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,912评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,449评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,500评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,370评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,193评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,074评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,505评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,722评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,841评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,569评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,168评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,783评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,918评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,962评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,781评论 2 354