02kotlin构造函数与接口

kotlin构造函数与接口

1.构造函数

1.constructor

constructor,有private等修饰时,需要

/**
 * 主构造函数
 *  一个类对象中,属性如果时val修饰,只生成
 */
class Person constructor(firstName: String) { /*……*/ }

/**
 * 简化写法,如果没有private或者注解修饰则可以省略constructor关键字
 */
class Person2(firstName: String) {}
class Person3 private constructor(firstName: String) {
    var firstName: String = firstName
}
2.主构造函数

所谓的主构造函数,就是头上的Person4

注意,init一定会执行

/**
 * 主构造函数不能包含任何的代码。初始化的代码可以放到以 init 关键字作为前缀的初始化块(initializer
 * 在实例初始化期间,初始化块按照它们出现在类体中的顺序执行,与属性初始化器交织在一起:
 */
class Person4(firstName: String, age: Int) {
    var firstName: String
    var age: Int

    init {
        this.firstName = firstName
        this.age = age
    }
}

简化写法

/**
 * 请注意,主构造的参数可以在初始化块中使用。它们也可以在类体内声明的属性初始化器中使用
 */
class Person5 private constructor(firstName: String) {
    var firstName: String = firstName
}

更简洁写法

/**
 * 更简洁的写法
 */
class Person6 private constructor(val firstName: String, var age: Int) {}

2.次构造函数


/**
 * 如果类中有主构造函数和次构造函数,则次构造函数一定要实现主构造函数
 */
class School2(val firstName: String, var age: Int) {
    var studentNum: Int = 0

    constructor(firstName: String, age: Int, studentNum: Int) : this(firstName, age) {
        this.studentNum = studentNum
    }
}
/**
 * 多个次构造函数时,也可以实现同类中其他次构造函数,间接地实现主构造函数
 */
class School3(val firstName: String, var age: Int) {
    var studentNum: Int = 0
    var name: String? = null

    constructor(firstName: String, age: Int, studentNum: Int) : this(firstName, age) {
        this.studentNum = studentNum
    }

    constructor(firstName: String, age: Int, studentNum: Int, name: String) : this(firstName, age, studentNum) {
        this.name = name;
    }
}

3.继承

kotlin中,如果表达一个类或者函数可以被继承,需要open关键字

如果向禁止继承的超类,在被继承函数,可以用final

1.方式1
open class Base(p: Int)

/**
 * 继承
 * 需声明一个显式的超类型,请在类头中把超类型放到冒号之后
 */
class Derived(p: Int) : Base(p)
2.方式2
/**
 * 默认情况下,Kotlin 类是最终(final)的:它们不能被继承。 要使一个类可继承,请用 open 关键字标记它。
 * 函数也一样,默认也是final标记地
 */
open class BaseTeacher(name: String) {
    open fun teach(lesson: String) {

    }

    fun eat(thing: String) {

    }
}

/**
 * 继承 二者必须实现一个
 * 1.没有构造方法时,继承需要class()形式
 * 2当父类有成员时,子类可以通过constructor来实现,但必须super去实现父类地构造函数
 */
class MathTeacher : BaseTeacher {//类似接口,但不是接口
    var name: String? = null

    constructor(name: String) : super(name) {
        this.name = name
    }

    override fun teach(lesson: String) {
        super.teach(lesson)
    }
}
3.禁止二次覆盖
/**
 * 如果想禁止二次被覆盖,可以在前面加上final关键字
 */
class Circle() : Shape() {
    final override fun draw() { /*……*/
    }
}

4.属性覆盖

kotlin中,属性覆盖也需要用open

1.覆盖属性
open class Shape2 {
    open val vertexCount: Int = 0
    open val height: Int = 2
    open val width: Int = 3
    open var length: Int = 5;
}

/**
 *  可以用一个 var 属性覆盖一个 val 属性,但反之则不行。
 *  这是允许的,因为一个 val 属性本质上声明了一个 get 方法,
 *  而将其覆盖为 var 只是在子类中额外声明一个 set 方法。
 *  java中没有属性继承的方式,但实际,也是覆盖了
 */
class Rectangle : Shape2() {
    override val vertexCount = 4
    override val height: Int
        get() = super.height

    //   override val height:Int = 4 // 可以覆盖
    override var width: Int = 10
//    override val length:Int = 2 // 不能将var变成val
}
2.获取父类属性
/**
 * 派生类中的代码可以使用 super 关键字调用其超类的函数与属性访问器的实现:
 */
open class Rectangle2 {
    open fun draw() {
        println("Drawing a rectangle")
    }
    val borderColor: String get() = "black"
}
class FilledRectangle : Rectangle2() {
    override fun draw() {
        super.draw()
        println("Filling the rectangle")
    }
    val fillColor: String get() = super.borderColor
}

5.内部类访问外部类

package day2Class

/**
 * 内部类与java本质时一样的,public final class Filler,非静态类
 * 一个内部类中访问外部类的超类,可以通过由外部类名限定的 super 关键字来实现
 */
class FilledRectangle2 : Rectangle2() {
    override fun draw() {
        println("你好")
    }

    inner class Filler {
        fun fill() {
            println("Filling")
        }

        fun drawAndFill() {
            super@FilledRectangle2.draw() // 调用 Rectangle 的 draw() 实现而不是FilledRectangle2的draw方法
            fill()
            draw()//调用FilledRectangle2的draw
            println("Drawn a filled rectangle with color ${super@FilledRectangle2.borderColor}") // 使用 Rectangle 所实现的 borderColor 的 get()
        }
    }
}

fun main(args: Array<String>) {
    var filler2: FilledRectangle2.Filler = FilledRectangle2().Filler()
    println(filler2.drawAndFill())
}

6.覆盖规则

package day2Class

/**
 * 可以同时继承 Rectangle 与 Polygon, 但是二者都有各自的 draw() 实现,
 * 所以我们必须在 Square 中覆盖 draw(), 并提供其自身的实现以消除歧义。
 */
open class Rectangle3 {
    open fun draw() { /* …… */
    }
}
interface Polygon3 {
    fun draw() { /* …… */
    } // 接口成员默认就是“open”的
}
class Square() : Rectangle3(), Polygon3 {
    // 编译器要求覆盖 draw():
    override fun draw() {
        super<Rectangle3>.draw() // 调用 Rectangle.draw()
        super<Polygon3>.draw() // 调用 Polygon.draw()
    }
}

7.抽象类

继承抽象方法时,不需要open和override关键字

package day2Class

open class Polygon4 {
    open fun draw() {}
}
/**
 * 抽象
 */
abstract class Rectangle4 : Polygon4() {
    abstract override fun draw()
}
/**
 * 继承抽象方法时,不需要open和override关键字
 */
class Rectangle5 : Rectangle4() {
    override fun draw() {
        TODO("Not yet implemented")
    }
}
abstract class Rectangle10 {
    abstract fun draw()
}
fun main(args: Array<String>) {
    //匿名类对象
    var r: Rectangle10 = object : Rectangle10() {
        override fun draw() {
            TODO("Not yet implemented")
        }
    }
}

8.属性声明

1.var和val
/**
 * var字段,默认会提供setter和getter方法
 * val字段,默认会提供getter方法
 */
class Address {
    var name: String = "Holmes, Sherlock"
    var street: String = "Baker"
    var city: String = "London"
    var state: String? = null // 允许空
    var zip: String = "123456"
}

注意下面:

/**
 * data关键字,默认
 * 所有属性的 getters (对于 var 定义的还有 setters)
 * equals()
 * hashCode()
 * toString()
 * copy()
 * 所有属性的 component1()、 component2()……等等
 *
 * 注意,不要去实现已经实现的方法,copy hashCode equals
 */
data class Address2(var name: String, var age: Int) {
//    fun copy(name: String, age: Int) {
//
//    }
}
2.属性幕后字段field

field就是counter.

/**
 * 幕后字段 field
 * getter和setter方法
 * field 关键字,代表当前属性的counter的值,只能使用在幕后字段中,	其他地方不能使用
 */
class Rule {
    var counter = 0 // 注意:这个初始器直接为幕后字段赋值
        set(value:Int) {
            if (value >= 0) field = value
        }
        get() {
            return if (field >= 0) field + 1 else 1
        }
}

9.延迟初始化

1.lateinit

lateinit,是延迟初始化属性,第一次使用之前需要赋值

/**
 * 使用注意
 * 在var之前添加lateinit,然后选择你想要的时候,初始化,但是有以下需要注意的地方:
 * lateinit只能修饰变量var,不能修饰常量val
 * lateinit不能对可空类型使用
 * lateinit不能对java基本类型使用,例如:Double、Int、Long等
 * 在调用lateinit修饰的变量时,如果变量还没有初始化,则会抛出未初始化异常,报错
 */
class Late {
    lateinit var a1: String
    fun test() {
        if (!this::a1.isInitialized) {
            a1 = "test1"
        }
        // 初始化
        println(a1)
    }
}
2.lazy 延迟初始化

​ lazy是延迟初始化,懒加载而且单例

    val a2: String by lazy {
        println("开始初始化")
        // 初始化的值
        "sss"
    }

10.接口

1.接口可以有非抽象函数
/**
 * 接口中属性要么是抽象的,要么提供访问器的实现
 * JDK1.8中,接口中无需全部是抽象函数,java中可以写上具体属性数据,或者方法,添加关键字default,
 * 说白了,接口和抽象类型几乎等价,甚至有的语言去掉了接口的概念,统一抽象类
 *
 */
interface MyInterface2 {
    val prop: Int  // 抽象的
    val propertyWithImplementation: String
        get() = "foo"
    fun foo() {
        print(prop)
    }
}
class Child2 : MyInterface2 {
    override val prop: Int = 29
}
2.接口属性被覆盖

接口提供属性时,从而既提供基类型成员的实现也声明新的函数与属性

/**
 * 个接口可以从其他接口派生,从而既提供基类型成员的实现也声明新的函数与属性
 * 实现接口时,就无需实现,默认会添加接口中的属性
 * 当作抽象类去理解更容易
 */
interface Person12 : Named {
    val firstName: String
    val lastName: String

    override val name: String get() = "$firstName $lastName"
}

data class Employee(
        // 不必实现“name”
        override val firstName: String,
        override val lastName: String,
        val position: Int
) : Person12

fun main(args: Array<String>) {
    var employee: Employee = Employee("1", "2", 3)
    println(employee.name)
}

11.SAM函数式编程

SAM函数编程,简单就是接口如同函数一样,省略,java1.8之后lamada匿名接口

package day2Class

import org.omg.CORBA.Object


/**
 * 只有一个抽象方法的接口称为函数式接口或 SAM(单一抽象方法)接口。
 * 函数式接口可以有多个非抽象成员,但只能有一个抽象成员。
 * 可以用 fun 修饰符在 Kotlin 中声明一个函数式接口,1.4新特性,
 * SAM函数编程
 */
interface KRunnable {
    fun invoke()
}

fun interface MyRun {
    fun run()
}

fun interface MyRun2 {
    fun run(a: Int)
}

fun runAction(a: MyRun) = a.run()

fun runAction2(k: () -> Unit) = k

fun runAction3(a: Int, b: MyRun2) = b.run(a)

fun String.runAction4(n: (String) -> Unit) = n(this)

interface IntPredicate {
    fun accept(i: Int): Boolean
}

fun setIntPredicate(a: IntPredicate) {

}

fun main(args: Array<String>) {
    /**
     * 匿名内部类接口
     */
    val isEven: IntPredicate = object : IntPredicate {
        override fun accept(i: Int): Boolean {
            return i % 2 == 0
        }
    }

    /**
     * 通过 lambda 表达式创建一个实例
     * 1.4新特性,当前编译器不知道什么原因不能使用(已更新到1,4-21)
     */

    var isEven2 = object : IntPredicate {
        override fun accept(i: Int): Boolean {
            return i % 2 == 0
        }
    }
    runAction(object : MyRun {
        override fun run() {
            println("你好")
        }
    })
    runAction {
        //实现接口方法
        println("你好")
    }

    runAction2 {

    }

    runAction3(2) { x ->
        println(x.plus(2))
    }
    var str = "xxxx"
    str.runAction4 {
        println(it)
    }
}

12.可见性修饰符

/**
 * 如果你不指定任何可见性修饰符,默认为 public,这意味着你的声明将随处可见;
如果你声明为 private,它只会在声明它的文件内可见;
如果你声明为 internal,它会在相同模块内随处可见;
protected 不适用于顶层声明。
 */

13.静态方法

在class外的都是静态属性,等价于java中添加static

package day2Class


fun method() {//java static fun method(){}

}

fun method2() {
}
fun method3() {

}

实现接口方法
println(“你好”)
}

runAction2 {

}

runAction3(2) { x ->
    println(x.plus(2))
}
var str = "xxxx"
str.runAction4 {
    println(it)
}

}


### 12.可见性修饰符

```kotlin
/**
 * 如果你不指定任何可见性修饰符,默认为 public,这意味着你的声明将随处可见;
如果你声明为 private,它只会在声明它的文件内可见;
如果你声明为 internal,它会在相同模块内随处可见;
protected 不适用于顶层声明。
 */

13.静态方法

在class外的都是静态属性,等价于java中添加static

package day2Class


fun method() {//java static fun method(){}

}

fun method2() {
}
fun method3() {

}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值