Kotlin语法入门-类与对象(6)
文章目录
六、类与对象
1、声明和调用
fun main() {
var a = A() // 面相函数式,所以不用new关键字也可以
a.print()
}
class A {
val a = 2
fun print() {
println(a)
}
}
2、get和set
在kotlin中,不能直接调用get和set方法,默认就是赋值就自动调用了set()方法,取值就自动调用get()方法。
就像下面这段示例,test.a = 5这个赋值操作调用set(),取值调用get():
fun main() {
var test = A()
test.a = 5
test.print()
}
class A {
var a = 2
get() {
return field - 1
}
set(value) {
field = value + 1
}
fun print() {
println(a)
}
}
输出结果:
3、init函数初始化
我们可以在类中添加初始化函数,每当创建一个类的对象之后,init方法就会自动调用,可以用于初始化数据
fun main() {
var test = A()
}
class A {
var a = 2
init {
println("A") //自动调用
}
}
通过传入值初始化:
fun main() {
var test = A(5)
}
class A(b: Int) {
var a = 2
init {
a = b
}
}
值得注意的是:在对对象传入值的之后可以同时对变量初始化,例如:
class A(var b: Int) {}
,就代表了b就成为了A对象的成员变量,kotlin语法支持这样写。但是只能在一级构造函数(主构造函数)上写这种,在二级构造函数中不支持这种语法,二级构造函数接下来有介绍。
4、constructor构造函数
在kotlin中奖构造函数分为主构造函数和次构造函数
4.1、主构造函数
class A constructor() {
var a = 2
init {
// 主构造函数的方法体
}
}
其中,主构造函数关键字constructor可以省略不写,其构造的方法体就在init函数中。
4.2、二级构造函数
class A constructor(var b: Int = 1) {
var a = 2
init {
println("init()...")
}
constructor() : this(3) { //代理主构造函数
println("次构造函数...")
}
}
注意:次构造函数需要主构造函数调用才能实现,即使用
this()
代理主构造函数,也可以传入参数this(3)
,可就是将b赋值为3。
这种方式就相当于java中的在构造方法中调用其他构造方法。
4.3、多个构造函数
class A constructor(var b: Int = 1) {
var a = 2
init {
println("init()...")
}
constructor(c: Int, d: Int) : this(3) {
println("次构造函数1...")
}
constructor() : this(1, 2) {
println("次构造函数2...")
}
}
当然,次构2不一定要代理次构1,也可以直接代理主构,但是次构1就失效了。
4.4、省略主构造函数并写了次构造函数
例如这种,就直接成为主构造函数了:
class A {
constructor(c: Int, d: Int) {
//此时识别为主构造函数
}
}
多态:
class A {
constructor(c: Int, d: Int) {
}
constructor(c: Int) {
}
}
5、类的继承与重写
5.1、继承
fun main() {
var b = B()
b.print()
}
open class A { //一定一定要添加open关键字
var a = 1
}
class B : A() {
var b = 2
fun print() {
println(a)
println(b)
}
}
一定一定要添加open关键字。
5.2、继承构造函数初始化
子类继承父类,子类要对父类进行构造方法的初始化:
1、主构造函数初始化:
open class AParent {
}
class AChild() : AParent() {
}
2、次构造函数初始化:
open class AParent {
}
class AChild : AParent {
constructor() : super(){}
}
3、父类多构造函数–子类主构造函数调用 :
当父类函数存在两个构造函数时,分别为主构造函数和二级构造函数:
open class AParent(name: String, age: Int) {
constructor(name: String) : this(name, 30)
}
子类函数2:
class AChild() : AParent( "A") {}
子类函数1:
class AChild() : AParent( "A",15) {}
上述两种方式都可以实现父类构造函数的初始化,图解:
3、父类多构造函数–子类副构造函数调用 :
赋值输出:
fun main() {
var aChild = AChild("rediaz")
aChild.print()
}
open class AParent(var name: String, var age: Int) {
constructor(name: String) : this(name, 30)
}
class AChild : AParent {
constructor(name: String) : super(name)
fun print(){
println("name: ${super.name}")
}
}
5.3、函数的重写
正常继承,默认无法进行重写:
它说需要override关键字,好嘛加上:
然后又说基类的方法关键字是final修饰的。
正确重写方式,在父类的成员方法中加上open关键字:
open class AParent() {
open fun A() { println("A") }
open fun B() { println("B") }
}
class AChild : AParent() {
override fun A() {}
override fun B() {}
}
5.4、属性的重写
这个是kotlin中特有的操作,Java中没有。
示例:
open class AParent() {
open val a = 1
open var b = 2
}
class AChild : AParent() {
override val a: Int
get() = super.a
override var b: Int
get() = super.b
set(value) {}
}
上述这种方式就实现了重写属性成员a和b,其中a是常量,b是变量,所以重写之后有点区别。
重写的时候可以直接赋值进行覆盖:
open class AParent() {
open val a = 1
open var b = 2
}
class AChild : AParent() {
override val a: Int = 0
override var b: Int = 0
}
但是底层还是有get和set方法
重写时将a的val换成var,则其会将代码编译成新的变量,并生成对应的get和set方法:
6、抽象类、嵌套类和内部类
6.1、抽象类
对于抽象类,其用法与Java无异
抽象是面向对象编程的特征之一,类本身,或类中的部分成员,都可以声明为abstract的。抽象成员在类中不存在具体的实现。
需要注意的是:不用对抽象类或抽象成员标注open注解。
abstract class AParent() { // 抽象类
abstract fun sum() // 抽象方法
}
class AChild : AParent() {
override fun sum() {
}
}
6.2、嵌套类
先上代码:
fun main() {
var aParent = AParent()
aParent.print()
var aChild = AParent.AChild()
aChild.print()
}
class AParent() { // 抽象类
fun print() {
println("外部类")
}
class AChild() {
fun print() {
println("嵌套类")
}
}
}
注:在Java中,这是一个内部类的一个写法,但是在koltin中,这种事属于内部类的一个写法。
嵌套类是被final关键字修饰的。
6.3、内部类
在嵌套类的基础上,在嵌套类的前面加上一个关键字inner就变成了内部类,并且可以访问外部类中的成员变量,使用this@类名
的方式。示例:
fun main() {
AParent().AChild().print()
}
class AParent() {
val a = 1
fun print() {
println("外部类")
}
inner class AChild() { //加上inner关键字
fun print() {
println("嵌套类")
println(this@AParent.a) //获取AParent中的a值
}
}
}