Kotlin --类/继承/接口/扩展


类定义

class Empty{// 与java定义类相似
	fun a(){
	}
}
//但 Kotlin 可定义空类
class Empty

类属性

/**
*类可以有一个主构造器以及一个或多个次构造器
*主构造器位于类名后
*如果主构造器没有任何注解,也没有任何可见修饰符,则可省略(注解和修饰符放在constructor前)
**/
class Person constructor(firstName:String){//class Person(FirstName:String)
	val name:String //不可变变量
	var age //可变变量
}
//用构造函数创建类实例,kotlin中没有关键字new
empty = new Person()
//引用类属性
empty.name
getter & setter
/*
属性声明的完整语法
*/
var <propertyName>[: <PropertyType>] [= <property_initializer>]
    [<getter>]
    [<setter>]

//val不允许设置setter函数,因为它不可修改
//如果属性类型可从初始化语句或类成员函数推断出来,则可省略类型
var allByDefault: Int? // 错误: 需要一个初始化语句, 默认实现了 getter 和 setter 方法
var initialized = 1    // 类型为 Int, 默认实现了 getter 和 setter
val simple: Int?       // 类型为 Int ,默认实现 getter ,但必须在构造函数中初始化
val inferredType = 1   // 类型为 Int 类型,默认实现 getter

实例

class Person {

    var lastName: String = "zhang"
        get() = field.toUpperCase()   // 将变量赋值后转换为大写
        set

    var no: Int = 100
    	//Kotlin 中类不能有字段。提供了 Backing Fields(后端变量) 机制,备用字段使用field关键字声明,field 关键词只能用于属性的访问器
        get() = field                // 后端变量
        set(value) {
            if (value < 10) {       // 如果传入的值小于 10 返回该值
                field = value
            } else {
                field = -1         // 如果传入的值大于等于 10 返回 -1
            }
        }

    var heiht: Float = 145.4f
        private set
    lateinit var m:Int //延迟初始化,否则一定要定义时初始化
}
主构造器

主构造器中不能含任何代码,初始化代码可以放在初始化代码段,初始化代码段以init作为前缀

class Person constructor(firstName:String){
	init{
	...
	}
}

/*
可通过主构造器定义属性并初始化
*/
class Person constructor(val firstName:String, var age:Int){
}
次构造器

如果类有主构造函数,每个次构造函数都要,或直接或间接通过另一个次构造函数代理主构造函数。在同一个类中代理另一个构造函数使用 this 关键字:

class Person(val name: String) {
    constructor (name: String, age:Int) : this(name) {
        // 初始化...
    }
}

如果一个非抽象类没有声明构造函数,它会自动生成一个无参数的public构造函数。如果你不想这个类有public构造函数,则需要自定义一个空的private构造函数:

class Person private constructor(){
}

抽象类

open class Base {
    open fun f() {}
}

abstract class Derived : Base() {
    override abstract fun f()
}

嵌套类

class Outer {                  // 外部类
    private val bar: Int = 1
    class Nested {             // 嵌套类
        fun foo() = 2
    }
}

fun main(args: Array<String>) {
    val demo = Outer.Nested().foo() // 调用格式:外部类.嵌套类.嵌套类方法/属性
    println(demo)    // == 2
}

内部类

关键字inner
内部类会带有一个对外部类的引用,要访问来自外部作用域的this,要使用this@label,label为外部类的类名

class Outer {
    private val bar: Int = 1
    var v = "成员属性"
    /**嵌套内部类**/
    inner class Inner {
        fun foo() = bar  // 访问外部类成员
        fun innerTest() {
            var o = this@Outer //获取外部类的成员变量
            println("内部类可以引用外部类的成员,例如:" + o.v)
        }
    }
}

fun main(args: Array<String>) {
    val demo = Outer().Inner().foo()
    println(demo) //   1
    val demo2 = Outer().Inner().innerTest()   
    println(demo2)   // 内部类可以引用外部类的成员,例如:成员属性
}

匿名内部类

使用对象表达式来创建匿名内部类

class Test {
    var v = "成员属性"

    fun setInterFace(test: TestInterFace) {
        test.test()
    }
}

/**
 * 定义接口
 */
interface TestInterFace {
    fun test()
}

fun main(args: Array<String>) {
    var test = Test()

    /**
     * 采用对象表达式来创建接口对象,即匿名内部类的实例。
     */
    test.setInterFace(object : TestInterFace {//object是关键字,不能用别的词替代!!
        override fun test() {
            println("对象表达式创建匿名内部类的实例")
        }
    })
}

类的修饰符

/*
classModifier: 类属性修饰符,标示类本身特性。
*/
abstract    // 抽象类  
final       // 类不可继承,默认属性
enum        // 枚举类
open        // 类可继承,类默认是final的
annotation  // 注解类
/*
accessModifier: 访问权限修饰符
*/
private    // 仅在同一个文件中可见
protected  // 同一个文件中或子类可见
public     // 所有调用的地方都可见
internal   // 同一个模块中可见


嵌套类和内部类

创建时
var demo = Outter.Nested() //嵌套类,Outter后没有括号
var demo = Outter().Inner()	//内部类,有括号

也就是说,要想构造内部类的对象,必须先构造外部类的对象,而嵌套类则不需要

引用外部类成员变量时

嵌套类内需要创建外部类实例再引用,内部类直接用this@



Any

Any是所有类的超类
class Example //从Any隐式继承

Any默认提供了三个函数
equals()
hashCode()
toString()


若一个类要被继承,可用open关键字进行修饰
open class Base(p:Int)
class Derived(p:Int):Base(p)


构造函数

若子类有主构造函数,则基类必须在主构造函数中立即初始化
open class Person(name:String)
class Student(name:String,id:String):Person(name)

子类无主构造函数,则必须在每一个二级构造函数中用super关键字初始化基类,或在代理另一个构造函数。

class Student:Person(){
	constructor(name:String):super(name)
	}


重写

重写方法

final修饰的方法不能被子类重写
–允许子类重写的方法要用open修饰,子类重写方法时要用override

open class Person{
	open fun f(){
	}
}

class Student:Person(){
	override fun f(){
	print("xx")
	}
}

多个相同方法(继承或实现自不同父类,则必须重写该方法,使用super去选择性调用父类的实现

open class A(){
	open fun f(){
		print("I m A")
		}
}

interface B(){
	open fun f(){
		print("I m B")
		}
}

class C:A(),B{
	override fun f(){
	super<A>.f()	//可不写
	super<B>.f()	//可不写
	}
}

C可继承A、B中共有的函数,重写时必须(?)调用A、B中该函数的实现,并提供自己的实现


属性重写

属性必须具有兼容类型才能被重写,每一个声明的属性都可以通过初始化程序或getter方法被重写

open class Base{
	open val x:Int get{...}
}

class Example:Base(){
	override var x:Int = ...
}

可用一个var属性重写一个val属性,反之不行。



接口

  1. 一个类或对象可继承多个接口
  2. 接口中的属性只能是抽象的,不允许初始化值,接口不会保存属性值,实现接口时,必须重写属性
interface MyInterface {
    var name:String //name 属性, 抽象的
    fun bar()
    fun foo() {
        // 可选的方法体
        println("foo")
    }
}
class Child : MyInterface {
    override var name: String = "runoob" //重写属性
    override fun bar() {
        // 方法体
        println("bar")
    }
}
fun main(args: Array<String>) {
    val c =  Child()
    c.foo();
    c.bar();
    println(c.name)
 
}

扩展

扩展是一种静态行为,对被扩展的类代码本身不会造成任何影响。

扩展函数

扩展函数可以在已有类中添加新的方法,不会对原类做修改。

fun receiverType.functionName(params){
    ...
}

/*
以下为实例
*/
class Example()

fun Example.Print(){
	print("halo")
	}

this关键字指代接收者对象(receiver object)(也就是调用扩展函数时, 在点号之前指定的对象实例)。

// 扩展函数 swap,调换不同位置的值
fun MutableList<Int>.swap(index1: Int, index2: Int) {
    val tmp = this[index1]     //  this 对应该列表
    this[index1] = this[index2]
    this[index2] = tmp
}

fun main(args: Array<String>) {

    val l = mutableListOf(1, 2, 3)
    // 位置 0 和 2 的值做了互换
    l.swap(0, 2) // 'swap()' 函数内的 'this' 将指向 'l' 的值

    println(l.toString())
}

若成员函数和扩展函数一致,优先使用成员函数

class C {
    fun foo() { println("成员函数") }
}

fun C.foo() { println("扩展函数") }

fun main(arg:Array<String>){
    var c = C()
    c.foo()	//输出结果为 成员函数
}

扩展空对象

在扩展函数内, 可以通过 this 来判断接收者是否为 NULL,这样,即使接收者为 NULL,也可以调用扩展函数。

fun Any?.toString(): String {
    if (this == null) return "null"
    // 空检测之后,“this”会自动转换为非空类型,所以下面的 toString()
    // 解析为 Any 类的成员函数
    return toString()
}
fun main(arg:Array<String>){
    var t = null
    println(t.toString())
}

扩展属性允许定义在类或者kotlin文件中,不允许定义在函数中。
– 扩展属性不允许被初始化,只能通过显式提供的setter/getter定义
扩展属性只能声明为val
val Example.age = 1 //错误


伴生对象的扩展

伴生对象通过"类名."形式调用伴生对象,伴生对象声明的扩展函数,通过用类名限定符来调用

伴生对象内的成员相当于Java 中的静态成员

class MyClass {
    companion object { }  // 将被称为 "Companion"
}

fun MyClass.Companion.foo() {
    println("伴随对象的扩展函数")
}

val MyClass.Companion.no: Int
    get() = 10

fun main(args: Array<String>) {
    println("no:${MyClass.no}")
    MyClass.foo()
}

扩展声明为成员

在一个类内部你可以为另一个类声明扩展。

分发接收者:扩展方法定义所在类的实例
扩展接收者:扩展方法的目标类型的实例

open class D {
}

class D1 : D() {
}

open class C {
    open fun D.foo() {
        println("D.foo in C")
    }

    open fun D1.foo() {
        println("D1.foo in C")
    }

    fun caller(d: D) {
        d.foo()   // 调用扩展函数
    }
}

class C1 : C() {
    override fun D.foo() {
        println("D.foo in C1")
    }

    override fun D1.foo() {
        println("D1.foo in C1")
    }
}


fun main(args: Array<String>) {
    C().caller(D())   // 输出 "D.foo in C"
    C1().caller(D())  // 输出 "D.foo in C1" —— 分发接收者虚拟解析
    C().caller(D1())  // 输出 "D.foo in C" —— 扩展接收者静态解析

}

假如在调用某一个函数,而该函数在分发接受者和扩展接受者均存在,则以扩展接收者优先,要引用分发接收者的成员你可以使用限定的 this 语法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值