《Kotlin核心编程》阅读笔记

第三章 面向对象

更简洁地构造类的对象

在Java中,通过重载构造函数,来实现任意参数组合来创建对象,但是这样需要实现的构造方法就会很多。
koltin的解决方法:

  • 构造函数默认参数;(如果这样做,在创建对象的时候,最好指定参数的名称)。
	class Bird(val weight:Double = 0.00,val age:Int = 0,val color:String ="blue")
	val bird1 = Bird(color = "black")
	val bird1 = Bird(1000.0,"blue",1)
   	val bird2 = Bird(color = "red",age = 5)	
  • init语句块 : 它属于上述构造方法的一部分,两者在表现的形式上是分离的。如果需要在构造初始化时进行其他的额外操作就可以使用init语句块。构造方法还可以拥有多个init,它们会在对象被创建时,按照类中从上到下的顺序先后执行。
    延迟初始化
    • by lazy :语法特点:该变量必须是引用不可变的(即使用val声明);在被首次调用时,才会进行赋值操作。一旦赋值,后续它将不能被更改。
      lazy 的背后是接受一个lambda并返回一个Lazy 实例的函数,第一次访问该属性时,会执行lazy对应的Lambda表达式并记录结果。后续访问时就返回该记录。
      系统会给lazy 属性默认加上同步锁,也就是LazyThreadSafetyMode.SYNCHRONIZED ,它在同一时刻只允许一个线程对lazy属性进行初始化,因此它是线程安全的。
      val sex by lazy(LazyThreadSafetyMode.PUBLICATION) { 
      	//并行模式
      	if(color == "yellow") "male" else "female"
      }
      val sex by lazy(LazyThreadSafetyMode.NONE) {
      	//不做任何线程保证也不会有任何线程开销
      	if(color == "yellow") "male" else "female"
      }
      
    • lateinit : 主要用于var 声明的变量,然而他不能用于基本数据类型,如Int,Long等,需要使用Integer这种包装类进行替代。
    主从构造方法:
    • 通过constructor 方法定义了一个新的构造方法,它被称为从构造方法。如果主构造方法存在注解或可见性修饰符,也必须像从构造方法一样加上constructor 关键字。
      每一个从构造方法有两部分组成,一部分是对其他构造方法的委托,另一部分是由花括号包裹的代码块。执行顺序上会先执行委托的方法,然后执行自身代码块的逻辑。
      通过this关键字来调用要委托的构造方法。如果一个类存在主构造方法,那么每一个从构造方法都要直接或间接地委托给它。

不同的访问控制原则

Kotlin中使用冒号":"来进行类的继承和接口的实现。
Kotlin中的类和方法默认是不可继承或重写的,有需要的话要加上open 修饰符。
子类应该尽量避免重写父类的非抽象方法,一旦父类变更方法,子类就方法调用就可能会出错。重写父类的非抽象方法违背了面向对象设计原则中的里氏代换原则

什么是里氏替换原则?

通俗的理解:子类可以扩展父类的功能,但是不能改变父类原有功能。
包含了4个设计原则:

  • 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法;
  • 子类可以增加实现自己特有的方法;
  • 当子类的方法实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
  • 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。
可见性修饰符
  • Kotlin 与 Java 的默认修饰符不同,Kotlin是 public ,而Java 中是 default。
  • Kotlin 中有一个独特的修饰符internal
  • Koltin 可以在一个文件内 单独声明方法及常量,同样支持可见性修饰符。
  • Java中出了内部类 可以用private 修饰以外,其他类都不允许private 修饰,而Kotlin可以。
  • Koltin和Java中的protected 的访问范围不同,Java中是包、类、及子类可访问,而Kotlin只允许类及子类。
    internal 在Kotlin中的作用域可以被称为 模块内访问 。什么算是一个模块呢?一个Eclipse项目,一个Intellij IDEA项目、一个Maven项目,一个Gradle项目,一组由一次Ant任务执行编译的代码

Kotlin 中的 private 修饰的类,表示它的作用域就是当前这个Kotlin文件。

在Koltin实现一个接口时:

  • 需要实现接口中没有默认实现的方法及未初始化的属性,若同时实现多个接口,而接口间又有相同方法名的默认实现时,需要主动指定使用那个接口方法或重写方法;
  • 如果是默认的接口方法,需要在实现类中通过"super" 这种方法调用它,
  • 在实现接口的属性和方法时,都必须带上override 关键字,不能省略。

Koltin在我们声明一个属性的时候,会帮助生成getter 和 setter 方法。

  • 用val 声明的属性将只有getter 方法,因为它不可修改,而用var 修饰的属性将同时拥有getter 和 setter 方法。
  • 用private 修饰的属性,编译器将会省略 getter 和 setter 方法,没有必要饿了,因为类外部无法访问。

如果我们要在Koltin中使用内部类,需要在类的前面加一个inner关键字。因为Koltin直接写在类中的类为嵌套类。这里的嵌套类可以看成Java中的静态内部类。

在某些场合下,内部类确实是一种解决多继承非常好的思路。

open class Horse{
    fun runFast(){
        println("I can run fast")
    }
}

open class Donkey{
    fun doLongTimeThing(){
        println("I can do thing long time")
    }
}
class Mule {
    fun runFast(){
        HorseC().runFast()
    }
    
    fun doLongTimeThing(){
        DonkeyC().doLongTimeThing()
    }
    
    private inner class HorseC:Horse()
    private inner class DonkeyC:Donkey()
    
}

使用委托代替多继承

委托是一种特殊的类型,用于方法事件委托,调用A类的methodA 方法,其实背后是B类的methodA 去执行。
在Koltin中,只需通过by关键字就可以实现委托的效果。

interface CanFly{
    fun fly()
}

interface CanEat{
    fun eat()
}

open class Flyer:CanFly{
    override fun fly() {
        println("I can fly")
    }
}

open class Animal:CanEat{
    override fun eat() {
        println("I can eat")
    }
}

class Bird(flyer: Flyer,animal: Animal):CanFly by flyer,CanEat by animal{}

fun main() {
    val flyer = Flyer()
    val animal  =Animal()
    val bird1 = Bird(flyer,animal)
    bird1.eat()
    bird1.fly()
}

用data class 创建数据类。

从static 到 object

在Kotlin中,引入了全新的关键字object,可以完美的代替使用static 的所有场景。object 还可以实现更多功能,比如单例对象及简化匿名表达式。

伴生对象(companion object):

"伴生"是相对于一个类而言,意为伴随某个类的对象,它属于这个类所有,因此伴生对象跟Java中static 修饰效果性质一样,全局只有一个单例,他需要声明在类的内部,在类被装载时会被初始化。
伴生对象也是实现工厂方法模式的另一种思路。

class Prize constructor(val name:String,val count:Int,val type:Int) {
    companion object{
        val TYPE_COMMON = 1
        val TYPE_REDPACK = 1
        val TYPE_COUPON = 1

        private val defaultCommonPrize = Prize("普通奖品",10,Prize.TYPE_COMMON)

        fun newRedPackPrize(name:String,count: Int) = Prize(name,count,Prize.TYPE_REDPACK)

        fun newCouponPrize(name: String,count: Int) = Prize(name,count,Prize.TYPE_COUPON)

        fun defaultCommonPrize() = defaultCommonPrize
    }
}


fun main() {
    val redpackPrize =Prize.newRedPackPrize("红包",10)
    val couponPrize = Prize.newCouponPrize("优惠卷",10)
    val commonPrize = Prize.defaultCommonPrize()
}

object 单例

单例模式最大的特点就是在系统中只能存在一个实例对象,所以在Java中我们必须通过设置构造方法私有化,以及提供静态方法创建实例的方式来创建单例对象。但是在Kotlin中可以直接使用object 来实现单例。

object 表达式

用于代替匿名内部类的object 表达式,在运行中不像之前的单例模式中说的那样,全局只存在一个对象,而是每一次运行时都会生成一个新的对象。

object表达式和Lambda表达式哪个更适合代替匿名类

当匿名内部类使用的类接口只需要实现一个方法时,使用Lambda 表达式更适合;当匿名内部类内有多个方法实现的时候,使用object 表达式更加合适。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值