开放式ETL产品 是 信创国产化替代“标配“(上篇)
Kotlin之面向对象
类
- 定义:使用class关键字进行定义。
-
class Dog {
}
- 在kotlin类中,除非显式地声明延迟初始化,否则就得指定属性的默认值。
- 在kotlin类中,成员默认是全局可见,而Java中,需要使用public才能达到此效果。
- 构造函数
- Kotlin将构造函数分为两种:主构造函数和次构造函数。
- ①主构造函数:
- 每个类默认都会有一个不带参数的主构造函数,也可以显式地给它指明参数。
- 可以给主构造函数的参数指定默认值。
-
class Dog(val name: String = "", val age: Int = 0, val color: Color = Color.BLUE)
创建:
val dog = Dog("wangwang")
val dog2 = Dog(color = Color.BLUE)
val dog3 = Dog("Tom", 1)
- 如果主构造函数中的变量被var或val修饰,表示这个变量相当于类的成员变量。此时如果再在类中定义同名变量会报错。
- 特点:没有函数体,直接定义在类名的后面即可。如果想在主构造函数中写一些逻辑可以放在init结构体中。
-
class Student(sno: String, grade: Int) : People() {
init {
}
}
class Student(sno: String, grade: Int, name: String, age: Int) : People(name, age) {
}
- 利用刚说的构造函数中参数的特性,我们有3种方式初始化:
- ①在构造函数中将参数指定为var或val,使其变为类的成员变量;
- ②不把构造函数中的参数指定为var或val,在类中定义同名的成员变量,并在init块中使用构造参数来进行初始化;
- ③不把构造函数中的参数指定为var或val,在类中定义同名的成员变量,并把构造参数赋值给成员变量。
-
class Dog(val name: String = "", val age: Int = 0) {
fun test() {
println("name = $name, age = $age")
}
}
class Dog(name: String = "", age: Int = 0) {
val name: String
val age: Int
init {
this.name = name
println("初始化块1:name = $name")
}
init {
this.age = age
println("初始化块2:age = $age")
}
fun test() {
println("name = $name, age = $age")
}
}
输出:
初始化块1:name = wangwang
初始化块2:age = 1
name = wangwang, age = 1
class Dog(name: String = "", age: Int = 0) {
val name: String = name
val age: Int = age
fun test() {
println("name = $name, age = $age")
}
}
- 延迟初始化:不想在创建对象时就初始化该属性。
- 可以使用lateinit和by lazy这两种语法来实现。
- ②次构造函数:
- 任何类只能有一个主构造函数,但可以有多个次构造函数。
- 次构造函数也可以用于实例化一个类,只不过它是有函数体的。
- Kotlin规定:当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数(也包括间接调用)。
- 次构造函数可能在自定义view时使用。
- 定义:次构造函数使用constructor关键字来定义。
-
class Student(sno: String, grade: Int, name: String, age: Int) : People(name, age) {
constructor(name: String, age: Int) : this("", 0, name, age) {
}
constructor() : this("", 0) {
}
}
使用:
val student1 = Student()
val student2 = Student("Tom", 18)
val student3 = Student("100", 7, "Jack", 17)
- 特殊情况:类中只有次构造函数,没有主构造函数。
- 次构造函数基本用不到,Kotlin提供了一个给函数设定默认值的功能,基本上可以代替次构造函数的作用。
对象
- 实例就是对象,对象就是实例。
- 创建对象:不再需要使用Java那样的new关键字。
接口
- Kotlin的接口基本和Java的接口一样。
- Kotlin和Java一样,最多只能继承一个类,实现一个或多个接口。
- Java实现接口使用implements关键字,kotlin不管是继承还是实现,都是用冒号:,之间使用逗号,分隔。
- 使用override关键字重写父类或实现接口中的函数。
- 支持定义抽象属性。
- 虽然kotlin的接口支持定义属性,但不能同时给它赋值:
val a: Int = 10
。 - 需要使用另一种方式来赋初值:
- 支持定义有默认实现的方法。
继承
- 在kotlin中,一个非抽象类默认是不可被继承的,相当于Java中给类声明了final关键字。需要给类加上open关键字。
- 继承需要使用冒号:,在Java中是使用extends关键字。
- 多继承:
- 特点:
- ①在实现一个接口时,需要实现接口中没有默认实现的方法及未初始化的属性。
- ②若要同时实现多个接口以及方法,同时又遇到同名的未实现的方法时,这个方法来自于谁已经不重要了,可以说它既来自类又来自接口,如果是同名的已实现的方法,要么重写方法,要么用“super”指定要调用哪个接口或类的方法。
- ③在实现接口或类的属性或方法时,必须要带上override关键字。
-
interface FlyAnimal {
val name: String
fun fly()
fun eat() {
println("FlyAnimal eat")
}
}
abstract class Animal {
abstract fun fly()
open fun eat() {
println("FlyAnimal eat")
}
}
class Bird(override val name: String) : Animal(),FlyAnimal{
override fun fly() {
println("fly")
}
override fun eat() = super<Animal>.eat()
}
fun main() {
val bird = Bird("lala")
bird.eat()
}
输出:
FlyAnimal eat
- 实现多继承的方式:
- ①使用多个接口模拟;
- ②使用内部类实现;
- 内部类:内部类使用inner class进行定义,如果不写,默认是静态内部类。
- 这种实现方式的优点:
- ③使用委托代替多继承:
- 使用by关键字实现委托。
- 优点:
- 1.接口是无状态的,即使可以在默认方法写逻辑,但也仅限于简单的逻辑,如果给它创建一个实现类,可以在其中编写更复杂的逻辑;
- 2.委托更加直观。
-
interface Fly {
fun fly()
}
interface Eat {
fun eat()
}
open class Flyer : Fly {
override fun fly() {
println("fly")
}
}
open class Animal : Eat {
override fun eat() {
println("eat")
}
}
class Bird(flyer: Flyer, animal: Animal) : Fly by flyer, Eat by animal {}
fun main() {
val bird = Bird(Flyer(), Animal())
bird.eat()
bird.fly()
}
输出:
eat
fly
可见性修饰符
- kotlin的可见性修饰符分4种:public、internal、protected、default。
- Java默认的可见性修饰符是default,不同于Java,Kotlin则是public。
- internal:我们开发了一个模块给别人使用,但是有一些函数只允许我们在模块内部调用,而不想暴露给外部,就可以用internal。
- 可见性修饰符功能一览表:
修饰符 | 可见性 |
---|
public | 所有类可见 |
internal | 同一模块中的类可见 |
protected | 当前类、子类可见 |
private | 当前类可见 |
伴生对象
- 意为某个类的对象,它属于这个类所有。
- 伴生对象和Java的static效果一样,全局只有一个单例。它需要声明在类的内部,在类被装载时进行初始化。
- 使用companion object进行定义,里面用来装类的静态变量和静态方法。
- 使用时直接用类名.。
- 在安卓中,我们可以给Fragment、Activity、Dialog定义一个伴生对象用来传递数据和启动等。
数据类
单例类
- 希望某个类在全局最多只能拥有一个实例。
- 在Java中创建单例类的步骤:
- (1)使类的构造方法私有化;
- (2)提供一个静态的getInstance()方法,用于给外部提供类的实例。
- 在kotlin中使用object关键字进行声明。
object表达式
- 相比于匿名内部类只能继承一个类或实现一个接口,object表达式却没有这个限制。
- 在安卓中,我们可以使用object表达式来代替匿名内部类,如常用的Listener接口等。
- 对于object表达式可以实现的一些场景,Lambda表达式也可以实现。具体建议参考如下:
- 当匿名内部类使用的类接口只需要实现一个方法时,使用Lambda更合适;当有多个方法需要实现时,则建议使用object表达式。