Kotlin笔记(3)

get和set方法

Kotlin中字段是私有的,会自动生成get、set方法。

fun main(args: Array<String>) {

    val person=Person()
    //表面看是直接访问了属性,其实是通过get方法
    println(person.name)
    println(person.age)
}

class Person{
    var name:String="haha"
    var age:Int=23
}
访问器可见性
class Person{
    var name:String="haha"
    var age:Int=23

    //需求:school字段不能外部修改
    var school:String="hehe"
    private set//私有了set方法
}
修改访问器

java中我们可以在set方法里处理一些逻辑,Kotlin中set方法是自动生成的,那我们如果想在里面处理逻辑,就要修改访问器了。

class Person{
    var name:String="haha"
    var age:Int=23
    set(value) {
        if(value<100){
            //this.age=value //这种造成递归
            field=value
        }
    }

    //需求:school字段不能外部修改
    var school:String="hehe"
    private set//私有了set方法
}
对象中init使用

需求:创建的时候就需要修改里面的name和age,也就是需要类似java中构造函数。

class Person(name:String,age:Int){
    var name:String=""
    var age:Int=0
    //构造函数中写的代码可以放到init中执行
    init {
        this.name=name
        this.age=age
    }
}

我们需要用变量保存构建函数的参数值,如上,写起来比java还麻烦,不过Kotlin中有简单的方案,就是用var和val来修饰构建函数参数。

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

}

//相当于java中这么写
class Person{
    public String name;
    public int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

那么,用var和val修饰的区别是什么?val修饰后,外部不可修改(不可赋值)。

次构函数
class Person(var name:String,var age:Int){

    var phone:String=""
    //次构函数
    constructor(name:String,age:Int,phone:String):this(name,age){
        this.phone=phone
    }
}
继承

Kotlin的类都是final的,不能被继承,需要加open

open class Father{
    open var name="百里屠苏"
    open fun smoke(){
        println("父亲喜欢抽烟")
    }
}

class Son:Father() {
    //继承属性
    override var name="百里少侠"

    //继承方法
    override fun smoke() {
        //super.smoke()
        println("百里少侠喜欢看书")
    }
}
抽象类
//抽象类不用open关键字
abstract class Human{
    //肤色
    abstract var color:String
    //语言
    abstract var language:String
    //吃饭
    abstract fun eat()
    fun sleep(){

    }
}

class CNHuman:Human(){
    override var color: String="黄色"
    override var language: String="中文"

    override fun eat() {
        println("使用筷子吃饭")
    }
}
接口

Kotlin跟java一样,是单继承多实现。
Kotlin中接口字段不能初始化,只能定义。可以有实现了的方法。

interface RideBike{
    fun ride()
}
interface DriveCar{
    var license:String
    fun drive()
    fun haha(){
        println("haha")
    }
}

class XiaoMing:CNHuman(),RideBike,DriveCar{
    override var license: String="12345"

    override fun drive() {
        println("学会了开车")
    }

    override fun ride() {
        println("学会了骑自行车")
    }

    //接口中已经实现,这里可以实现也可以不实现
    override fun haha() {
        println("hahhahahah")
    }
}
智能类型转换
abstract class Person

class XL:Person(){
    fun sleep(){
        println("躺着睡觉")
    }
}

class XM:Person(){
    fun sleep(){
        println("站着睡觉")
    }
}
val xm1=XM()
xm1.sleep()

val xm2:Person=XM()
if(xm2 is XM){
    //java中的思路是判断后还要强转
    //val newXM=xm2 as XM
    //newXM.sleep()

    //Kotlin中判断后就可以使用了
    xm2.sleep()
}
嵌套类和内部类
  • Kotlin中嵌套类是静态类,跟外部类环境没有关系。
  • 内部类依然外部类环境
//嵌套类
class OutClass{
    var name="haha"
    class InnerClass{
        //无法访问name
    }
}


//内部类
class OutClass{
    var name="haha"
    inner class InnerClass{
        //可以访问name
    }
}

//嵌套类创建
val innerClass=OutClass.InnerClass()
//内部类创建
val innerClass=OutClass().InnerClass()



class OutClass{
    var name="haha"
    inner class InnerClass{
        var name="hehe"
        fun sayHello(){
            //访问的是自己的name
            println(name)
            //访问外部类name
            println(this@OutClass.name)
        }
    }
}
泛型
  • 泛型类
open class Box<T>(thing:T){

}
//继承的时候知道具体类型
class FruitBox(thing: Fruit):Box<Fruit>(thing){

}
//继承的时候不知道具体类型
class SonBox<T>(thing: T):Box<T>(thing){

}

abstract class Fruit{

}
class Apple:Fruit(){

}

//定义对象的时候使用泛型
val box=Box("haha")
  • 泛型函数
fun  parseType(thing: T){
    when(thing){
        is Int-> println("Int类型")
        else-> println("不知道")
    }
}


parseType(10)
parseType("百里屠苏")
  • 泛型上限

泛型上限:泛型只能是X类或者X类的子类。限制存放的类型。

  • 泛型擦除
//java里面必须通过反射获取泛型类型

val box1=Box("haha")
val box2=Box(10)
//class类型
val clz1=box1.javaClass.name
val clz2=box2.javaClass.name

//上面我们声明了Box泛型类,并实例化了两种类型的实例:String、Int,但是获取类名时却得到了相同的结果cn.gxh.day01.Box,这是因为在编译器擦除了泛型类型声明。


//解决泛型擦除方案:
//第一步:泛型前加reified
//第二步:方法前加上inline关键字
inline fun  parseType(thing: T){
    val name=T::class.java.name
    println(name)
}
  • 泛型类型投射
fun setFruitList(list:ArrayList<Fruit>){//接收的是Fruit的集合
    println(list.size)
}

//下面我们创建Apple的集合传进去,发现不可以(Apple是Fruit的子类)
val list=ArrayList<Apple>()
setFruitList(list)//此处不可以


//out相当于java中的? extends
fun setFruitList(list:ArrayList<out Fruit>){//接收的是Fruit或者其子类的集合
    println(list.size)
}

//out解决了我们遇到的问题,但是我们想传Fruit或者其父类的集合又怎么办呢?

//in相当于java中的? super
fun setFruitList(list:ArrayList<in Fruit>){//接收的是Fruit或者其父类的集合
    println(list.size)
}
  • 星号投射
//如果我的ArrayList想接收任何类型的数据,可以使用泛型T,不过Kotlin提供了一个简单的方案,就是星号投射。
fun <T> setList(list:ArrayList<T>){
}
fun setList2(list:ArrayList<*>){
}

你可能感兴趣的:(Kotlin笔记)