Kotlin learning: Kotlin classes and objects

Kotlin classes and objects

Class definition

Kotlin classes can contain: constructors and initialization code blocks, functions, properties, internal classes, object declarations

Kotlin uses the keyword class to declare a class, followed by the class name

class Runoob {  // 类名为 Runoob
    // 大括号内是类体构成
}

You can also define an empty class

class Empty

Member functions can be defined in the class

class Runoob() {
    fun foo() { print("Foo") } // 成员函数
}

Class attributes

Attribute definition

The properties of the class can be declared as mutable with the keyword var, otherwise declared as immutable with the read-only keyword val

class Runoob {
    var name: String = ……
    var url: String = ……
    var city: String = ……
}

We can use constructors to create class instances like normal functions

val site = Runoob() // Kotlin 中没有 new 关键字

To use an attribute, just refer to it by name

site.name           // 使用 . 号来引用
site.url

A class in Koltin can have a primary constructor and one or more secondary constructors. The primary constructor is part of the class header and is located after the class name

class Person constructor(firstName: String) {}

If the main constructor does not have any annotations and no visibility modifiers, then the constructor keyword can be omitted

class Person(firstName: String) {
}

getter 和 setter

The complete syntax of the attribute declaration

var <propertyName>[: <PropertyType>] [= <property_initializer>]
    [<getter>]
    [<setter>]

Both getter and setter are optional

If the attribute type can be inferred from the initialization statement or the member function of the class, then the type can be omitted, and val does not allow the setter function to be set, because it is read-only

var allByDefault: Int? // 错误: 需要一个初始化语句, 默认实现了 getter 和 setter 方法
var initialized = 1    // 类型为 Int, 默认实现了 getter 和 setter
val simple: Int?       // 类型为 Int ,默认实现 getter ,但必须在构造函数中初始化
val inferredType = 1   // 类型为 Int 类型,默认实现 getter

Instance

The following example defines a Person class, which contains two variable variables lastName and no. LastName modifies the getter method, and no modifies the setter method.

class Person {

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

    var no: Int = 100
        get() = field                // 后端变量
        set(value) {
            if (value < 10) {       // 如果传入的值小于 10 返回该值
                field = value
            } else {
                field = -1         // 如果传入的值大于等于 10 返回 -1
            }
        }

    var heiht: Float = 145.4f
        private set
}

// 测试
fun main(args: Array<String>) {
    var person: Person = Person()

    person.lastName = "wang"

    println("lastName:${person.lastName}")

    person.no = 9
    println("no:${person.no}")

    person.no = 20
    println("no:${person.no}")

}

Output result

lastName:WANG
no:9
no:-1

Classes in Kotlin cannot have fields. Provides a Backing Fields (back-end variable) mechanism, the alternate fields are declared with the field keyword, and the field keyword can only be used for attribute accessors, as in the above example

Non-empty properties must be initialized when they are defined. Kotlin provides a solution that can be initialized later, using the lateinit keyword to describe properties

public class MyTest {
    lateinit var subject: TestSubject

    @SetUp fun setup() {
        subject = TestSubject()
    }

    @Test fun test() {
        subject.method()  // dereference directly
    }
}

Main constructor

The main constructor cannot contain any code, the initialization code can be placed in the initialization code segment, and the initialization code segment uses the init keyword as a prefix

class Person constructor(firstName: String) {
    init {
        println("FirstName is $firstName")
    }
}

Note: The parameters of the main constructor can be used in the initialization code segment, and can also be used in the attribute initialization code defined by the class body n. A concise syntax, you can define attributes and initialize attribute values ​​through the main constructor (it can be var or val)

class People(val firstName: String, val lastName: String) {
    //...
}

If the constructor has annotations or visibility modifiers, then the constructor keyword is required, and the annotations and modifiers should be placed before it

Instance

Create a Runoob class and pass in the website name through the constructor

class Runoob  constructor(name: String) {  // 类名为 Runoob
    // 大括号内是类体构成
    var url: String = "http://www.runoob.com"
    var country: String = "CN"
    var siteName = name

    init {
        println("初始化网站名: ${name}")
    }

    fun printTest() {
        println("我是类的函数")
    }
}

fun main(args: Array<String>) {
    val runoob =  Runoob("菜鸟教程")
    println(runoob.siteName)
    println(runoob.url)
    println(runoob.country)
    runoob.printTest()
}

Output result

初始化网站名: 菜鸟教程
菜鸟教程
http://www.runoob.com
CN
我是类的函数

Subconstructor

Classes can also have secondary constructors, which need to be prefixed with constructor

class Person { 
    constructor(parent: Person) {
        parent.children.add(this) 
    }
}

If the class has a primary constructor, each secondary constructor must, or directly or indirectly proxy the primary constructor through another secondary constructor. Use this keyword to proxy another constructor in the same class

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

If a non-abstract class does not declare a constructor (primary constructor or secondary constructor), it will generate a constructor with no parameters. The constructor is public. If you don’t want your class to have a public constructor, you have to declare an empty main constructor

class DontCreateMe private constructor () {
}

Note: In the JVM virtual machine, if all the parameters of the main constructor have default values, the compiler will generate an additional constructor without parameters, and this constructor will directly use the default values. This makes it easier for Kotlin to use libraries like Jackson or JPA that use parameterless constructors to create class instances

class Customer(val customerName: String = "")

Instance

class Runoob  constructor(name: String) {  // 类名为 Runoob
    // 大括号内是类体构成
    var url: String = "http://www.runoob.com"
    var country: String = "CN"
    var siteName = name

    init {
        println("初始化网站名: ${name}")
    }
    // 次构造函数
    constructor (name: String, alexa: Int) : this(name) {
        println("Alexa 排名 $alexa")
    }

    fun printTest() {
        println("我是类的函数")
    }
}

fun main(args: Array<String>) {
    val runoob =  Runoob("菜鸟教程", 10000)
    println(runoob.siteName)
    println(runoob.url)
    println(runoob.country)
    runoob.printTest()
}

Output result

初始化网站名: 菜鸟教程
Alexa 排名 10000
菜鸟教程
http://www.runoob.com
CN
我是类的函数

Abstract class

Abstraction is one of the characteristics of object-oriented programming. The class itself, or some members of the class, can be declared as abstract. There is no concrete realization of abstract members in the class.

Note: There is no need to mark open annotations on abstract classes or abstract members

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

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

Nested class

We can nest the class in other classes, see the following examples

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 class

The inner class is represented by the inner keyword.

The inner class will have a reference to the object of the outer class, so the inner class can access the member properties and member functions of the outer class

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)   // 内部类可以引用外部类的成员,例如:成员属性
}

In order to eliminate ambiguity, to access this from an external scope, we use this@label, where @label is a label that refers to the source of this

Anonymous inner class

Use object expressions to create anonymous inner classes

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 {
        override fun test() {
            println("对象表达式创建匿名内部类的实例")
        }
    })
}

Pay special attention to the object here: TestInterFace. This object is a keyword of Kotlin. To implement an anonymous inner class, you must use the object keyword. You cannot replace other words at will, remember to remember

Class modifier

Class modifiers include classModifier and accessModifier

classModifier: class attribute modifier, indicating the characteristics of the class itself

abstract    // 抽象类  
final       // 类不可继承,默认属性
enum        // 枚举类
open        // 类可继承,类默认是final的
annotation  // 注解类

accessModifier: access modifier

private    // 仅在同一个文件中可见
protected  // 同一个文件中或子类可见
public     // 所有调用的地方都可见
internal   // 同一个模块中可见

Instance

// 文件名:example.kt
package foo

private fun foo() {} // 在 example.kt 内可见

public var bar: Int = 5 // 该属性随处可见

internal val baz = 6    // 相同模块内可见

 

Guess you like

Origin blog.csdn.net/PrisonJoker/article/details/113666885