Kotlin学习(4)类与面向对象编程

mac2026-06-13  0

1. 声明类

1.1 空类

使用class 关键声明类,我们可以声明一个什么都不干的空类:

//声明类 class EmptyClass fun main(args: Array<String>){ val emptyClass = EmptyClass() }

1.2 声明类和构造函数

在Kotlin中,我们可以在声明类的时候同时声明构造函数,语法格式是在类的后面使用括号包含构造函数的参数列表。

class Person(val name: String, val age: Int){ override fun toString(): String { return "Person(name='$name',age=$age" } } }

其中val可以换成var。我们可以在代码中这样使用Person类:

val person = Person("Rikka",22) println("person = ${person}") //输出: person = Person(name='Jack', age=22)

另外,也可以先声明属性,等构造示例对象的时候再去初始化属性值,那么Person类可以进行如下说明:

class Person() { //lageinit关键字表示该属性将延迟初始化 lateinit var name: String //lateinit关键字不能修饰primitive类型 var age: Int = 0 }

我们可以在代码中这样创建Person的示例对象:

val person = Person() person.name = "Rikka" person.age = 22 ....

如果我们想声明一个具有多种构造方式的类,可以使用 constructor关键字声明构造函数。

class Person() { //如果在声明的时候加了括号,就说明有无参的构造函数 lateinit var name: String var age: Int = 0 constructor(name: String) : this() { this.name = name } constructor(name: String, age: Int) : this() { this.name = name this.age = age } }

1.3 抽象类

下面是声明一个抽象类,并展示继承代码

abstract class Shape //声明抽象父类Shape class Rectangle : Shape() //声明一个Rectangle继承抽象的Shape

抽象的概念与Java一样,它不能被实例化,我们只能实例化继承它的子类 抽象类的属性和继承如下:

abstract class Shape { abstract var height : Double abstract var width : Double abstract fun area() : Double } //继承了类同时也声明了构造函数 class Rectangle(override var width:Double, oveeride var height:Double) : Shape(){ ovrride fun area() : Double{ return height * width } } //....代码中调用 val r = Rectangle(2.0, 1.0) println(r.area())

和Java一样,如果在抽象类里面声明非抽象函数,子类是可以直接调用的。

抽象父类的非抽象函数默认都是final的,不可以被覆盖重写,如果想要开放给子类重新实现这个函数,可以在前面加上 open 关键字

abstract class Shape{ ... open fun sayHeollo() { println("say Hello") } }

1.4 接口

和Java类似,Kotlin使用interface作为接口的关键字

//声明一个空接口 interface ProjectService //声明一个有属性的接口 interface ProjectService { val name: String val owner: String fun save(project: Project) fun print(){ println("hello") } }

继承接口和继承类一样,也是使用 :,如果有多个接口,则用 , 隔开。

重写覆盖: 假如我们实现了两个 有相同函数的接口,并且在重写的时候使用了:

override fun xxx(){ super.xxx() }

这个时候会报编译错误,因为编译器不知道你要调用 超类的函数是哪一个。需要使用下面语法来正确调用:

super<XXXInterface>.xxx() //指定是具体哪一个接口

1.5 object对象

单例模式可以保证一个类在整个系统中只有一个实例。 而Kotlin中没有静态属性和方法,但是可以使用 object关键字声明一个object单例对象

object User { //声明一个对象类型User val username: String = "rikka" val password: String = "123456" fun hello() { println("Hello,object !") } } //直接调用 println(User.hello()) println(User.username)

Kotlin中还提供了伴生对象,用 companion object 关键字声明。 一个类只能有一个伴生对象

class DataProcessor{ companion object DataProcessor{ //声明了一个伴生对象 fun process() { println("hello companion") } } } fun main(args : Array<String>) { DataProcessor.process() //直接调用伴生对象的方法 }

可以看出来,在Kotlin中,不用特地去做实现单例模式的过程。 它有自己的单例实现方法:

类声明为 object class在类中用 companion object声明一个可以直接使用其属性和方法的伴生类。

1.6 数据类

在Java中,我们经常要去写大量的 getter&setter,虽然Android Studio通过快捷键可以一键创建,但是看起来不够简洁。 在kotlin中,我们就不用去在代码中充斥着这种代码,我们可以通过 关键字data class 来创建数据类

data class User(val name: String, val password: String)

这个类会省去getter、setter,并且自动创建 equals()/toString()、copy()、component1()、component2() 函数。

数据类的语法限制:

主构造函数至少包含一个参数参数必须标识为 val或者 var不能为 abstract、open、sealed或者inner不能继承其他类。

另外,数据类可以在解构声明中使用:

fun main(args: Array<Sring>){ val user = User("Rikka","123") val (name, password) = user //解构声明 println("name = ${name}, password = ${password}") } //输出: name = Rikka, password = 123

Pair和Triple Kotlin提供了 Pair 和Triple数据类,分别表示二元组和三元组。

val (i, j, k) = Triple(1, "a", 2.0) val (a, b) = Pair(4, "5") //可用用Pair对象来初始化一个Map val map = mapOf(Pair(1, "A"), Pair("2", "B")) //也可以这么写 val map = mapOf(1 to "A", 2 to "B")

1.7 注解

注解是将元数据附加到代码中。元数据信息由注解kotlin.Metadata定义。

@Retention(AnnotationRetention.RUNTIME) @Target(AnnotationTarget.CLASS) internal annotation class Metadata

这个@Metadata信息存在与Kotlin编译器生成的所有类文件中,并由编译器和反射读取。 例如,使用Kotlin声明一个注解的代码:

annotation class Suspendable

Kotlin中使用关键字 annotation class来声明注解类。 对应的Java代码如下:

@interface Suspendable

Kotlin编译器会为注解生成对应的元数据信息。具体什么样子就不看了= = Java看的还不够多吗 Kotlin的注解完全兼容Java的注解。

1.8 枚举

Kotlin中使用enum class:

enum class Direction { NORTH, SOUTH, WEST, EAST }

枚举类内置 String和Int类型,String表示 name,Int表示ordinal,也就是说它的值可以是String或者int

val north = Direction.NORTH north.name >NORTH north.ordinal >0

声明一个带构造参数 的枚举类:

enum class Color(val rgb: Int){ RED(0xFF0000) GREEN(0x00FF00) BLUE(0x0000FF) } val c = Color.GREEN c >GREEN c.rgb >65280 c.ordinal >1 c.name >GREEN

1.9 内部类

1.9.1 普通嵌套类 一个类可以嵌套在其它类中。而且可以嵌套多层:

class ClassDemo{ class Outer{ private val zero: Int = 0 val one: Int = 1 class Nested{ fun getTwo() = 2 class Nested1 { val three = 3 fun getFour() = 4 } } } } //使用 val four = ClassDemo.Outer.Nested.Nested().getFour()

和Java一样嵌套类是没有持有外部类的引用的,所以无法访问外部类的变量。

1.9.2 嵌套内部类 如果一个类Inner想要访问外部类的成员,则要在这个内部类修饰的时候加 inner

inner class Inner{ println(zero) }

1.9.3 匿名内部类 就是没有名字的内部类,它是可以访问外部类变量的:

class NestedClassDemo{ var isRunning = false; fun doRun(){ Thread(object: Runnable{ //匿名内部类 override fun run(){ isRunning = true; } }).start() } }
最新回复(0)