【kotlin】运算符重载,面向对象,泛型

运算符重载

kotlin中每一个运算符都是对应的一个方法,运算符相当于方法的简写
operator,找到对应的函数,在函数前面加上operator

class demo5 {
    //运算符重载,重载+方法
    operator fun plus(num: Int): Int {
        var i = num
        var sum = 0
        while (i > 0) {
            sum += i
            i--
        }
        return sum
    }

    //运算符重载,重载-方法
    operator fun minus(num: Int): Int {
        var i = num
        var sum = 0
        while (i > 0) {
            sum += i
            i--
        }
        return sum
    }

    operator fun rangeTo(num: Int):Int{
        var i = num
        var sum = 0
        while (i > 0) {
            sum += i
            i--
        }
        return sum
    }
}

fun main() {
    val demo5 = demo5()
    println(demo5 - 10)//相当于调用demo5.minus(10)方法
    println(demo5..100)
}
  • 底层java代码

在这里插入图片描述

get和set

  • kotlin中的字段是私有的,会自动生成get/set方法,如果是var修饰,则会生成get/set,如果是val修饰,则会生成get

在这里插入图片描述

在这里插入图片描述

  • 如何让外部代码禁止修改字段?,不能使用val,如果使用val,内部也无法修改
    var age: Int = 10
        private set
  • 在set中添加逻辑
    var age: Int = 10
        set(value) {//value是外部传递进来
            //field相当于age的值
            //不能直接修改age属性:age = value //error,相当于死递归了
            //field = value

            if (value == 100) {
                field = 10
            } else if (value == 101) {
                field = 20
            } else {
                field = -1
            }
        }

面向对象

构造函数

主构函数

一个类中最多只能一个主构函数,也可以没有,在类名后面

class Person(name: String, age: Int) {}
//或者
class Person constructor(name:String,age:Int){}

主构造器声明属性

  • 有参构造函数,属性只能在构造函数中使用
class Person(var name: String, val age: Int) {

}
//或者
class Person(name:String){
	var name:String = name
}

次构函数

相当于java中的构造函数重载
次构函数中的字段不能使用var/val,只能在外部定义字段,然后字段赋值
当定义次构函数时,必须调用主构函数(直接或间接)
无论调用主构函数还是次构函数都会执行init

	var phone:String=""

    constructor(name: String, age: Int, phone: String) : this(name, age) { //this(),也是相当于java中调用其他的构造函数
		this.phone = phone
    }

	//错误
	constructor(name: String, age: Int, phone: String){}
   

主构造器,init和次构函数的执行顺序

主构造器优先执行,接着执行init代码块,最后执行次构造函数。
主构造器相当于头部,init相当于颈部,次构造器相当于身体

封装

隐藏功能实现的细节,暴露外部所需要功能的接口

继承

kotlin中的class都是final,不能被继承
需要在类前面添加open关键字,该类才能被继承
使用 class C : P(参数列表)
属性继承也是一样,在java中属性的get/set也是final修饰,也需要open
方法也是需要使用open,才能被继承

fun main() {
    val p: People = Student()
    println(p.name)
    println(p.age)
    p.say()
}

open class People(open var phone: String) {
    open var name: String = ""//默认是final的,需要添加open关键字,去掉final
    var age = 0

    open fun say() {

    }
}

class Student : People("888") {
    //相当于重新了get/set
    override var name: String = "张三"//属性前面需要添加override关键字
    
	override var phone: String = "11223365"

    override fun say() {
        println("student say")
    }
}

抽象类

抽象类中不需要open关键字
和java一样,抽象类中可以没有抽象方法
和java一样,也是单继承
抽象类也是可以继承抽象类

fun main() {
    val man :Human = ZhMan()
    man.say()
}

abstract class Human {
    //底层是set/get方法抽象
    protected abstract var color: String

    abstract var lang: String

    abstract fun say()
}

class ZhMan : Human() {
    //重新了父类的方法
    override var color: String = "黄色"
    override var lang: String = "中文"

    override fun say() {
        println("我是zhman:${color},${lang}")
    }
}

接口

接口实现也是使用冒号 class C : P
接口可以多实现
kotlin中接口中的字段是不能实现的,底层是set/get方法。java中接口字段必须实现,而且是static final的,相当于常量

interface ICallback {
    //接口中的字段不能实现,其实底层也是set/get
    var i: Int
}

//实现接口
class demo1 : ICallback {
    override var i : Int
        get() {
            return 10
        }
        set(value) {}
}

public interface ICallback {
   int getI();

   void setI(int var1);
}

如果在接口定义常量,需要使用伴生对象,底层java代码是,在接口中定义了一个静态内部类

interface ICallback {
    companion object {
        const val NAME = ""
        fun say() {}
    }

    //接口中的字段不能实现,其实底层也是set/get
    var i: Int
}

kotlin接口中方法时可以默认实现的,底层java其实是在接口中定义了一个静态内部类实现了此接口,实现了该方法,当外部实现此接口时,会在该方法中,创建该静态内部类,从而调用了该抽象方法。

interface ICallback {
    //接口中方法可以实现
    fun hello() {
        println("hello")
    }
}
public interface ICallback {
	void hello();

	public static final class DefaultImpls {
	      public static void hello(@NotNull ICallback $this) {
	         String var1 = "hello";
	         boolean var2 = false;
	         System.out.println(var1);
	      }
	   }
}

//调用时

   public static final void main() {
      (new ICallback() {
         private int i = 10;

         public int getI() {
            return this.i;
         }

         public void setI(int var1) {
            this.i = var1;
         }

         public void hello() {
            ICallback.DefaultImpls.hello(this);
         }
      }).hello();
   }

智能类型转换

使用is关键字,判断类型是否相同
使用as关键字,进行类型强转
如果使用is判断了,则会智能推断出当前对象为指定的类型,不需要强转

	//强转
	val newMan = man as ZhMan
	
    val man :Human = ZhMan()
    if (man is ZhMan){//智能转换
        man.say()
    }

内部类

局部内部类

可以定义在方法中,与java一致

fun main() {
    class Inner{

    }
}

成员内部类和静态内部类

class Out{
    //静态内部类
    class StaticInner{

    }
    
    //成员内部类
    inner class Inner{
        //使用外部属性和方法时,使用this@外部类名
        this@Out.xxx
    }
}

匿名内部类

    //匿名内部类
    val obj = object : Inner() {}

泛型

泛型类

和java一致,泛型定义在类上,用<>表示
成员属性和成员方法也可以使用类泛型
静态属性和静态方法就不能使用类泛型。类一加载时,静态属性和静态方法就加载了,这时无法确定类的泛型类型
与java的泛型一致

fun main() {
    val demo8 = Demo8<String>()
    demo8.say("张三")
}

class Demo8<U> {
    var name: U? = null

    companion object {
        //静态属性和静态方法无法使用类泛型
        //和java一样
        //类一加载时,静态属性和静态方法就加载了,这时无法确定类的泛型类型
        var n: U? = null//错误,编译不通过
        fun staticSay(u: U) {//错误,编译不通过

        }

        //定义泛型方法
        fun <J> staticSay2(j: J) {
            println(j)
        }
    }

    //方法使用类泛型
    fun say(u: U) {
        println(u)
    }
}

泛型方法

和java的泛型方法一致

        //定义泛型方法
        fun <J> staticSay2(j: J) {
            println(j)
        }

泛型限定

泛型定义,该类型或该类型的子类

class FruitBox< f : Fruit> 只能存放Fruit或Fruit的子类
和java一样,在类上定义泛型时,只能是该类型或者该类型的子类,不能定义该类型的父类

  • java
class Person<E extends Number>{}

//没有接收类型的父类
class Person<E super Number>{}//错误

泛型插除

参数化类型的泛型参数只在编译期间有效,在运行期间就被插除了

获取泛型类型

	//获取类上的泛型类型
    fun haha() {
        val cls = thing!!::class.java
        println(cls)
    }

	//获取方法的泛型类型
    fun <E> haha2(name: E) {
        val cls = name!!::class.java
        println(cls)
    }
inline reified 获取泛型类型
    inline fun <reified E> haha3(name: E) {
        val cls = E::class.java//这里只是渐变的写法,直接使用泛型获取类型,不需要使用对象获取
        println(cls)
    }

泛型类型投射

泛型通配符,这里是使用泛型,注意和类泛型的声明(定义)区别

泛型的上限Out

接收当前类型或它的子类,相当于java中的<? extends Type>

	fun f1(list: ArrayList<out Fr>) {
	
	}
    static void say(List<? extends Number> list){

    }
泛型的下限in
	fun f1(list: ArrayList<in Fr>) {
	
	}
    static void say(List<? super Number> list){

    }

泛型星号投射

*相当于java中的?,可以传递任意类型

	fun f1(list: ArrayList<*>) {
	
	}
    static void say(List<?> list) {

    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值