Kotlin 学习记录一进阶

163 阅读7分钟

# Kotlin 学习记录一进阶

类与对象

主要是说明 Kotlin 中的面向对象概念。

函数

1. 函数的结构

//函数的声明
fun putPrint(s: String): String{
    printIn(s)
    return s
}
//函数的调用
putPrint("Hello World")

2. 函数的返回值

//在函数方法后面加上 : 返回类型
fun add(x: Int,y: Int): Int{
    return x + y
}

//没有返回类型的话
fun test(){
}

fun test(): Unit{
}//Unit类似于Java中的void

3. 函数的参数

//声明一个加法函数
fun add(x: Int,y: Int): Int{
    return x + y
}
//调用
add(1,2)

//命名参数
add(x=1,y=2)

//位置参数命名参数混用
fun test(a: String,b: String,c: String,d: String){
}
//调用:命名参数必须在位置参数之后
test("1","2",c="3",d="4")

//无法确定参数,变参,底层通过数组传递,可接受多个参数,也可以接受零个参数
fun sum(vararg n: Int): Int{
    var rel = 0
    for(a in n){
        rel += a
    }
    return rel
}
//调用
sum()
sum(1)
sum(1,2)
sum(1,2,3)

//传入数组到变参中,使用*号
val intArray = intArrayOf(1,2,3)
sum(*intArray)

//参数中的默认值
fun test(name: String,age: Int = 19){
}
//调用
test("xiaoming")

4. 函数返回值

//定义一个取绝对值函数
fun abs(x: Int): Int{
    if(x > 0){
        return x
    } else {
        return -x
    }
}

//可以简化为
fun abs(x: Int) = if(x > 0) x else -x

//语法
[访问控制符] class 类名{
    属性
    方法
}

//在Kotlin中当一个类没有实体时,可以省略{}
class A(val a: String)

//定义一个电脑类
class Computer{
    //cpu数量
    var cpu = 2
    //容量
    var disk = 1024
    
    //方法
    fun running(){
        printIn("运行中")
    }
    
    fun turnOn(){
        printIn("启动中")
    }
    
    fun shutDown(){
        printIn("关闭中")
    }
}
    

构造方法

1. 主构造方法

Kotlin 中主构造方法有且只有一个,所有的对象创建时必须使用主构造方法进行初始化,主构造方法紧随类的声明之后

//语法
class 类名 访问控制符 constructor (属性){
}

//例子
class Button (var test: String = "click",val with: Int,val height: Int){
}

//初始化代码块儿
class Button constructor(var test: String,val with: Int,val height: Int){
    //初始化代码块儿,跟随类对象实例化被调用
    init{
        
    }
}


2. 副构造方法

作用是辅助主构造方法来创建对象,一个类只能有一个主构造方法,但是可以拥有零个或者无数个副构造方法

class Button constructor(var test: String,val with: Int,val height: Int){
    
    //副构造方法一,调用主构造方法
    constructor(text: String): this(text,0,0)
    
    //副构造方法二,调用主构造方法
    constructor(with: Int, hright: Int): this("",with,height)
    
    //副构造方法三,调用副构造方法一
    constructor():this("默认按钮")
 
}

//创建对象
//调用主构造方法
var button1 = Button("click",100,100)
//调用副构造方法一
var button2 = Button("click")
//调用副构造方法二
var button3 = Button(100,100)
//调用副构造方法三
var button4= Button()

属性

Kotlin 中只能定义属性,属性既可以定义在类中,也可以定义在构造方法中,属性在定义之后几必须进行初始化。

1. 默认的Getter和Setter

//创建电脑类
//val 只读类型
class Computer(val disk: String) {
    //可读可写类型
    var cpu: Int = 0
    
}

fun main(){
    val computer = Computer("200GB")
    //默认调用Setter
    computer.cpu = 2
    //默认调用Getter
    val disk = computer.disk
}

2. 延迟初始化属性

使用延迟初始化

  • 必须定义在类中
  • 必须使用默认访问器
  • 必须声明var
  • 必须是非空类型
  • 必须是非基本数据类型
class MainActivity {
    //声明延迟初始化属性
    lateinit var button: Button
    
    
    fun onCreate(){
        //初始化属性
        button = Button()
        button.text = "OK"
    }
}

3. 内联属性

内联属性要求:数据值有访问器没有幕后字段

class Student{
    var loginName = ""
    inline var username: String
        get() = loginName
        set(value){
            this.loginName = value
        }
}

方法

方法就是定义在类中的函数,使用方法和使用函数类似。

1. infix方法

被infix修饰的方法,在调用时可以省略点符号和括号,注意这种方法只能有一个参数。

class Student{
    var height = 0
    //infix修饰的方法
    infix fun height(height: Int) {
        this.height = height
    }
}

fun main(){
    //创建对象
    val student = Student()
    //方式一普通调用
    student.height(180)
    //方式二 infix特性调用,省略点符号和括号,但是需要加空格
    student height 180
}

2. componentN方法

这种方法主要用于获取对象属性值

class Student(val name: String){
    var height: Int = 0
    
    operator fun component1(): String{
        return name
    }
    
    operator fun component2(): Int{
        return height
    }
}

//调用
val student = Student("xiaoming")
student.height = 180

val name = student.component1()
val height = student.component2()

类进阶

1. 嵌套类

嵌套类是一种定义在类内部的类,嵌套类与外部类都是独立的存在,无法访问外部类的成员。

//外部类
class Outer{
    val outProperty: String = "外部类属性"
    
    //嵌套类
    class Nested{
        val nestedProperty: String = "内部类属性"
        fun doSomthing(){
            printIn(outProperty)//无法访问
        }
    }
}

//创建对象
//通过 外部类.嵌套类 创建嵌套类
val nested = Outer.Nested()
//调用嵌套类方法
nested.doSomthing()

2. 内部类

内部类使用关键字 inner 修饰,定义在类内部的类,作为外部类的成员存在了,可以访问外部类的成员。

//外部类
class Outer{
    val name: String = "外部类属性"
    
    //内部类
    inner class Nested{
        val nestedProperty: String = "内部类属性"
        fun getOutName() = name
    }
}

//创建对象,外部类创建的时候同时会创建内部类对象
val out = Outer()
//通过外部类对象创建内部类对象
val nested = out.Inner()
//访问外部类属性
nested.getOutName()

单例对象

单例对象被 object 修饰,这种类只有一个实例,并且在创建过程中是线程安全的。

//单例对象
object Singleton{
    private var num = 0
    
    fun sum(): Int{
        num += 1
        return num
    }
}

//调用
printIn(Singleton.sum())//打印1
printIn(Singleton.sum())//打印2
printIn(Singleton.sum())//打印3

伴生对象

伴生对象是一种 companion 关键字修饰的、定义在类中的单例对象。伴生对象在声明时可以省略类名。一个类只能有一个伴生对象。

class Dialog(val title: String,val message: String){
    companion object Factory{
        fun do()
    }
}

//调用
Dialog.Factory.do()
Dialog.do()

对象表达式——匿名类

//创建接口
interface Valuable{
    fun getPrice(): Int
}
//创建抽象类
abstract class Item{
    abstract var group: String
}

fun main(){
    var bluBottle = object : Item(),Valuable{
        override fun getPrice(): Int {
            return 100
        }

        override var group = "药物"
    }

    System.out.println(bluBottle.group)
}

//直接创建匿名对象
val redBottle = object {
    fun getPrice(): Int{
        return 100
    }
    
    var group = "药物"
}

//匿名对象类型限制
//将匿名对象保存到本地变量或者私有属性,或者将匿名对象作为私有方法的返回值
//那么程序可以获得匿名对象的真实类型,并且访问到宁明对象中的成员

//将匿名对象定义为共有方法的返回值或者公有属性
//那么程序中只能获得匿名对象 的父类,无法访问对象表达式中的成员
open class Parent{
    val y: String = "y"
}

class Child{
    //私有方法
    private fun privateM() = object: Parent{
        val x: String = "x"
    }
    
    //公有方法
    fun publicM() = object: Parent{
        val x: String = "x"
    }
    
    fun text(){
        //调用私有方法创建的对象,返回真实类型
        val privateM = privateM()
        //访问对象表达式中的属性
        privateM.x
        //访问父类型中的属性
        privateM.y
        
        //调用公有方法创建对象,返回父类型的Parent
        val publicM = publicM()
        //只能访问父类型中的属性
        publicM.y
    }
}

继承

在 Java 中所有的类默认都可以被继承,而 Kotlin 相反,所有类默认都隐式被 final 修饰,无法被继承,想要实现继承功能需要:

  • 在父类声明语句的最前面加上 open 关键字;
  • 在子类声明语句之后加上 : 和父类类型
open class Parent{}

class Son: Parent(){}

//子类调用父类构造
open class View(val width: Int,val height: Int)

//子类一,调用父类主构造方法
class SmallView(width: Int,height: Int): View(width,height)
//子类二,调用父类副构造方法
class DefaultView : View()
//子类三,副构造方法调用了父类的主构造方法
class ListView: View{
    constructor(width: Int,height: Int): super(width,height)
}


//子类重写父类方法
open class View(val width: Int,val height: Int){
    //使用open声明该方法可以被重写
    open fun onDraw(){
    }
}

class SmallView(width: Int,height: Int) : View(width,height){
    override fun onDraw(){
        //调用父类的onDraw方法
        super.onDraw()
    }
}


//子类重写父类属性
open class View(val width: Int,val height: Int){
    //使用open声明该属性可以被覆写
    open var size: Int = 0
}

//方式一通过赋值语句重写
class SmallView(width: Int,height: Int) : View(width,height){
    override var size: Int = width * height
}

//方式二通过Getter访问器重写
class SmallView(width: Int,height: Int) : View(width,height){
    override var size: Int = width * height
        get() = width * height
}


//子类访问父类的成员
open class View(val width: Int,val height: Int){
    //使用open声明该属性可以被覆写
    open var size: Int = 0
}

class SmallView(width: Int,height: Int) : View(width,height){
    override var size: Int = width * height
    
    inner class Painter{
        //内部类访问外部类成员
        fun getOutSizeClass(): Int = size
        //内部类访问外部类父类成员
        fun getOutSuperClass(): Int = super@SmallView.size
    }
}