Kotlin核心编程(六)

本文介绍了Kotlin中的面向对象编程特性,包括类的定义、构造方法、初始化块(init)、延迟加载(bylazy和lateinit),以及主从构造方法。同时,文章还讨论了接口的默认方法、限制修饰符(如open和final)和密封类的概念。此外,提到了Kotlin与Java中可见性的差异,如internal修饰符。
摘要由CSDN通过智能技术生成

Kotlin核心编程(六)

面向对象

定义一个类

/*定义一个类*/
class Bird{
    val weight:Double = 500.0
    val color:String = "blue"
    val age:Int = 1
    fun fly(){

    }
}
/*编程成Java代码*/
/*public final class Bird {
   private final double weight = 500.0;
   @NotNull
   private final String color = "blue";
   private final int age = 1;

   public final double getWeight() {
      return this.weight;
   }

   @NotNull
   public final String getColor() {
      return this.color;
   }

   public final int getAge() {
      return this.age;
   }

   public final void fly() {
   }
}
*/
/*
不可变属性成员。Kotlin⽀持⽤val在类中声明引⽤不可变的属性成员,这是利⽤Java中的final修饰符来
实现的,使⽤var声明的属性则反之引⽤可变。
属性默认值。因为Java的属性都有默认值,⽐如int类型的默认值为0,引⽤类型的默认值为null,所以在声明属性的时候我们不需
要指定默认值。⽽在Kotlin中,除⾮显式地声明延迟初始化,不然就需要指定属性的默认值。
不同的可访问修饰符。Kotlin类中的成员默认是全局可见,⽽Java的默认可见域是包作⽤域,因此在Java版本中,我们必须采⽤
public修饰才能达相同的效果。
*/

val bird = Bird() //实例化对象

构造方法

/*改写Bird类,声明构造方法*/
/*1.构造方法默认参数*/
class Bird(val wight:Double=0.0,val age:Int=0,val color:String="Blue"){
    fun fly(){
        println("wight is ${wight},age is ${age},color is ${color}")
    }
}
val bird = Bird(wight = 2.3, color = "green") //实例化对象
    bird.fly()
>>wight is 2.3,age is 0,color is green // 输出

/* 
1、我们在Bird类中可以⽤val或者var来声明构造⽅法
的参数。这⼀⽅⾯代表了参数的引⽤可变性,另⼀⽅⾯它也使得我们
在构造类的语法上得到了简化。
2、事实上,构造⽅法的参数名前当然可以没有
val和var,然⽽带上它们之后就等价于在Bird类内部声明了⼀个同名
的属性,我们可以⽤this来进⾏调⽤。⽐如我们前⾯定义的Bird类就
类似于以下的实现:*/

/*2、构造参数名前没有val 和 var*/
class Bird1(wight:Double=0.0,age:Int=0,color:String="Blue"){
    var wight:Double
    var age:Int
    var color:String
    init {  // 构造方法参数可以在init语句块中被调用
        this.color = color
        this.age=age
        this.wight=wight
    }
    fun fly(){
        println("wight is ${wight},age is ${age},color is ${color}")
    }
}

init语句块

/*它属于上述构造⽅法的⼀部分,两者在表现形式上却是分离的。Bird类的构造⽅法在类的外
部,它只能对参数进⾏赋值。如果我们需要在初始化时进⾏其他的额外操作,那么我们就可以使⽤init语句块来执⾏*/
class Bird2(weight: Double, age: Int, color: String) {
    init {
        println("do some other things")
        println("the weight is ${weight}")
    }
}
/* 当没有val或var的时候,构造⽅法的参数可以在init语句块被直接调⽤。 */
//其实它们还可以⽤于初始化类内部的属性成员的情况。如:
class Bird1(wight:Double=0.0,age:Int=0,color:String="Blue"){
    var wight:Double=wight  //在初始化属性成员时调⽤wight
    var age:Int=age
    var color:String=color
    fun fly(){
        println("wight is ${wight},age is ${age},color is ${color}")
    }
}
// 除此之外,我们并不能在其他地⽅使⽤构造⽅法的参数!!!!
/* 我们的构造⽅法还可以拥有多个init,它们会在对象被
创建时按照类中从上到下的顺序先后执⾏*/

延迟化加载->by lazy和lateinit

/*再来思考⼀种场景,现实中我们在创建⼀个类对象时,很可能不需要对所有属性都进⾏传值。其中存在⼀些特殊的属性,⽐如鸟的性
别,我们可以根据它的颜⾊来进⾏区分,所以它并不需要出现在构造⽅法的参数列表中。
有了init语句块的语法⽀持,我们很容易实现这⼀点。假设黄⾊的鸟⼉都是雌性,剩余的都是雄鸟,我们就可以如此设计:*/
class Bird(val weight:Double,val age:Int,val color: String){
    val sex:String
    init {
        this.sex = if (this.color=="yellow") "male" else "female"
    }
}

/*我们再来修改下需求。这⼀次我们并不想在init语句块中对sex直
接赋值,⽽是调⽤⼀个专门的printSex⽅法来进⾏,如:*/

class Bird(val weight:Double,val age:Int,val color: String){
    var sex:String  // 报错:Property must be initialized or be abstract
    fun printSex(){
        this.sex = if(this.color=="yellow") "male" else "female"
        println(this.sex)
    }
}
/*
1、正常情况下,Kotlin规定类中的所有⾮抽象属性成员都必须在对象创建时被初始化值。
2、由于sex必须被初始化值,上述的printSex⽅法中,sex会被视为⼆次赋值,这对val声明的变量来说也是不允许的
*/

// .延迟初始化:by lazy和 lateinit
class Bird(val weight:Double,val age:Int,val color: String){
    lateinit var sex:String
    
    fun printSex(){
        this.sex = if(this.color=="yellow") "male" else "female"
        println(this.sex)
    }
}
/*
lateinit主要⽤于var声明的变量,然⽽它不能⽤于基
本数据类型,如Int、Long等,我们需要⽤Integer这种包装类作为替
代。
*/

class Bird(val weight:Double,val age:Int,val color: String){
    val sex:String by lazy {
        if(this.color=="yellow") "male" else "female"
    }
}
/*
总结by lazy语法的特点如下:
·该变量必须是引⽤不可变的,⽽不能通过var来声明。
·在被⾸次调⽤时,才会进⾏赋值操作。⼀旦被赋值,后续它将不能
被更改。
·lazy的背后是接受⼀个lambda并返回⼀个Lazy<T>实例的函数,
第⼀次访问该属性时,会执⾏lazy对应的Lambda表达式并记录结
果,后续访问该属性时只是返回记录的结果。*/


Delegates.notNull

让⽤var声明的基本数据类型变量也具有延迟初始化的效果

var test by Delegates.notNull<Int>()
    fun doSomething(){
        test=1
        println("Test value is ${test}")
    }

主从构造方法

/*先把Bird类简化为:*/
class Bird(age:Int){
    val age : Int
    init {
        this.age=age
    }
}
/*假设当前我们知道鸟的⽣⽇,希望可以通过⽣⽇来得到鸟的年龄,然后创建⼀个Bird类对象。如何实现?*/
class Bird(age:Int){
    val age : Int
    init {
        this.age=age
    }
    constructor(birth: DateTime) : this(getAgeByBirth(birth)) {
       ...
    }
    private fun getAgeByBirth(birth: DateTime): Int {
        return Years.yearsBetween(birth,Day)
    }
}
/*
* 1.通过constructor⽅法定义了⼀个新的构造⽅法,它被称为从构造⽅
法。相应地,我们熟悉的在类外部定义的构造⽅法被称为主构造⽅法
* 2.每个类可最多存在⼀个主构造⽅法和多个从构造⽅法,如果主构造⽅
法存在注解或 可见性修饰符, 也必须像从构 造⽅法⼀样加 上
constructor关键字
* 3.每个从构造⽅法由两部分组成。⼀部分是对其他构造⽅法的委托,
另⼀部分是由花括号包裹的代码块。执⾏顺序上会先执⾏委托的⽅法,
然后执⾏⾃⾝代码块的逻辑。
* 4.通过this关键字来调⽤要委托的构造⽅法。如果⼀个类存在主构
造⽅法,那么每个从构造⽅法都要直接或间接地委托给它。⽐如,可
以把从构造⽅法A委托给从构造⽅法B,再将从构造⽅法B委托给主构
造⽅法*/

可带有属性和默认⽅法的接口

/*定义一个接口*/
interface Flyer{
    val speed:Int  // 抽象属性
    fun kind()
    fun fly(){  // 带方法实现的接口
        println("I can fly")
    }
}
/*反编译成java代码:
* public interface Flyer {
   int getSpeed();

   void kind();

   void fly();

   public static final class DefaultImpls {
      public static void fly(@NotNull Flyer $this) {
         String var1 = "I can fly";
         System.out.println(var1);
      }
   }
}
*  现Kotlin编译器是通过定义了⼀个静态内部类DefaultImpls 来提供fly⽅法的默认实现的
* */

/*在接口中实现属性申明,不能直接赋值一个常量,得使用get()方法*/
interface Flyer1{
    val height get() = 1000
}

限制修饰符

open class Bird{
    open fun fly(){
        println("I can fly")
    }
}

class Penguin: Bird(){
    override fun fly() {
        println("I can't fly actually")
    }
}
/*·Kotlin中没有采⽤Java中的extends和implements关键词,⽽是使⽤“ :” 来代替类的继承和接⼜实现;
* ·由于Kotlin中类和⽅、法默认是不可被继承或重写的,所以必须加上open修饰符。
* ·类的默认修饰符:final,在Kotlin中的类或⽅法默认是不允许被继承或重写的
* ·在Java中,类默认是可以被继承的,除⾮你主动加final修饰符。⽽在Kotlin中恰好相反,默认是不可被继承的,
*   除⾮你主动加可以继承的修饰符,那便是之前例⼦中的open。*/

密封类

Kotlin除了可以利⽤final来限制⼀个类的继承以外,还可以通过
密封类的语法来限制⼀个类的继承。⽐如我们可以这么做:

sealed class Bird{
    open fun fly() = "I can fly"
    class Eagle :Bird()
}
/*Kotlin通过sealed关键字来修饰⼀个类为密封类,若要继承则需
要将⼦类定义在同⼀个⽂件中,其他⽂件中的类将⽆法继承它。*/

image.png

可见修饰符

  1. Kotlin与Java的默认修饰符不同,Kotlin中是public,⽽Java中是default。
  2. Kotlin中有⼀个独特的修饰符internal。
  3. Kotlin可以在⼀个⽂件内单独声明⽅法及常量,同样⽀持可见性修饰符。
  4. Java中除了内部类可以⽤private修饰以外,其他类都不允许private修饰,⽽Kotlin可以。
  5. Kotlin和Java中的protected的访问范围不同,Java中是包、类及⼦类可访问,⽽Kotlin只允许类及⼦类。
  6. internal在Kotlin中的作⽤域可以被称作“ 模块内访问” 。那么到底什么算是模块呢?以下⼏种情况可以算作⼀个模块:
    1. ⼀个Eclipse项⽬
    2. ⼀个Intellij IDEA项⽬
    3. ⼀个Maven项⽬
    4. ⼀个Grandle项⽬
    5. ⼀组由⼀次Ant任务执⾏编译的代码
    6. ⼀个模块可以看作⼀起编译的Kotlin⽂件组成的集合。

image.png

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Liknana

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值