- 一、接口
- 1. 简单使用
- 2. 接口中的函数使用
- 3. 接口中的属性使用
- 4. 接口的冲突问题解决
- 二、枚举类
- 1. 声明方式及枚举常量
- 2. 枚举常量的初始化
- 3. 枚举常量的匿名类
- 4. 枚举类的使用
- 5. 源码分析
Kotlin 也是面向对象编程。面向对象的语言是可以创建类的。类就是对事物的一种封装,比如人、汽车、房子等任何事物,我们都可以将它们封装成一个类,而类中又可以拥有自己的字段和函数。
一、接口 1. 简单使用- 声明
关键字:interface 定义格式: interface 接口名 { … }
- 用法
- 使用冒号( : ),这一点是和Java不同的。Java中使用接口使用的是implements关键字
- 在Kotlin中冒号( : ) 使用的地方很多:用于变量的定义、用于继承、用于接口、方法的返回类型声明 使用格式: class 类名 : 接口名 { // 重写的接口函数、属性等 … }
- 实例
/**
* 我定义的接口
*/
interface Demo1Interface{
// 定义的方法
fun fun1()
}
/**
* 接口的实现类
*/
class Demo1 : Demo1Interface{
override fun fun1() {
println("我是接口中的fun1方法")
}
}
fun main(args: Array) {
// 类的初始化
var demo = Demo1()
demo.fun1()
}
输出结果:
我是接口中的fun1方法
2. 接口中的函数使用不带结构体的函数可以省略大括号,且不用强制重写带结构体的函数就可以直接调用。不太明白也没关系,下面的代码中都有注释。
interface Demo2Interface{
/**
* 定义一个无参数无返回值的方法
*/
fun fun1()
/**
* 定义一个有参数的方法
*/
fun fun2(num: Int)
/**
* 定义一个有参数有返回值的方法
*/
fun fun3(num: Int) : Int
// 下面的两个方法是有结构体, 故可以不重写
/**
* 定义一个无参数有返回值的方法
*/
fun fun4() : String{
return "fun4"
}
/**
* 定义一个无结构体函数,大括号是可以省略的
*/
fun fun5(){
// 如果函数中不存在表达式,大括号可以省略。
// 如fun1一样
}
}
class Demo2 : Demo2Interface{
override fun fun1() {
println("我是fun1()方法")
}
override fun fun2(num: Int) {
println("我是fun2()方法,我的参数是$num")
}
override fun fun3(num: Int): Int {
println("我是fun3()方法,我的参数是$num,并且返回一个Int类型的值")
return num + 3
}
override fun fun4(): String {
println("我是fun4()方法,并且返回一个String类型的值")
/*
接口中的fun4()方法默认返回”fun4“字符串.
可以用super.fun4()返回默认值
也可以不用super关键字,自己返回一个字符串
*/
return super.fun4()
}
}
fun main(args: Array) {
var demo = Demo2()
demo.fun1()
demo.fun2(5)
println(demo.fun3(10))
println(demo.fun4())
//可以不重写该方法直接调用
demo.fun5()
}
输出结果:
我是fun1()方法 我是fun2()方法,我的参数是5 我是fun3()方法,我的参数是10,并且返回一个Int类型的值 13 我是fun4()方法,并且返回一个String类型的值 fun4
3. 接口中的属性使用在接口中申明属性。接口中的属性要么是抽象的,要么提供访问器的实现。接口属性不可以有后备字段。而且访问器不可以引用它们。
3.1 作为抽象 即重写属性的时候是在实现类的类参数中。这也是用代码提示去重写的实现方法
interface Demo3Interface{
val num1: Int
val num2 : Int
}
class Demo3(override val num1: Int, override val num2: Int) : Demo3Interface{
fun sum() : Int{
return num1 + num2
}
}
fun main(args: Array) {
var demo = Demo3(1,2)
println(demo.sum())
}
输出结果:
3
3.2 作为访问器 即手动方式去实现重写,并提供 get() 方法
interface Demo3Interface{
// 声明变量并提供默认值
// 注意: val num3: Int = 3 这种方式不提供,直接报错
val num3: Int
get() = 3
val num4: Int
}
class Demo3(override val num1: Int, override val num2: Int) : Demo3Interface {
// 提供访问器实现
override val num3: Int
get() = super.num3
// 手动赋值
override var num4: Int = 4
fun result() : Int{
return num3 + num4
}
}
fun main(args: Array) {
println(demo.result())
// 在这里也可以改变接口属性的值
demo.num4 = 10
println(demo.result())
}
输出结果:
7 13
4. 接口的冲突问题解决该问题是指当我们在父类中声明了许多类型,有可能出现一个方法的多种实现。
interface Demo4InterfaceOne{
fun fun1(){
println("我是Demo4InterfaceOne中的fun1()")
}
fun fun2(){
println("我是Demo4InterfaceOne中的fun2()")
}
}
interface Demo4InterfaceTwo{
fun fun1(){
println("我是Demo4InterfaceTwo中的fun1()")
}
fun fun2(){
println("我是Demo4InterfaceTwo中的fun2()")
}
}
class Demo4 : Demo4InterfaceOne,Demo4InterfaceTwo{
override fun fun1() {
super.fun1()
super.fun1()
}
override fun fun2() {
super.fun2()
super.fun2()
}
}
fun main(args: Array) {
// 类的初始化
val demo = Demo4()
demo.fun1()
demo.fun2()}
输出结果:
我是Demo4InterfaceOne中的fun1() 我是Demo4InterfaceTwo中的fun1() 我是Demo4InterfaceOne中的fun2() 我是Demo4InterfaceTwo中的fun2()
说明:Demo4 实现了 Demo4InterfaceOne
和 Demo4InterfaceTwo
两个接口,而两个接口中都存在两个相同方法名的方法。因此编译器不知道应该选哪个,故而我们用super.方法名来区分。
- 关键字:enum
- 枚举常量:即枚举类下的对象,每个枚举类包含0个到多个枚举常量。
- 声明 enum 关键字在类头中的 class 关键字前面 声明格式:
enum class 类名{
...
}
- 枚举常量
枚举类中的每一个枚举常量都是一个对象,并且他们之间用逗号分隔。
栗子:关于一个网络请求结果的枚举类
enum class State {
/*
NORMAL : 正常
NO_DATA : 数据为空
NO_INTERNET : 网络未连接
ERROR : 错误
OTHER : 其他
*/
NORMAL,NO_DATA,NO_INTERNET,ERROR,OTHER
}
- 访问枚举常量
不需要实例化枚举类就可以访问枚举常量
使用方式为:
枚举类名.枚举常量.属性
// 使用中缀符号访问枚举常量
State.NORMAL.name
State.NO_DATA.name
State.NO_INTERNET.name
State.ERROR.name
State.OTHER.name
2. 枚举常量的初始化
因为每一个枚举都是枚举类的实例,所以他们可以是初始化过的。
enum class Color(var argb : Int){
RED(0xFF0000),
WHITE(0xFFFFFF),
BLACK(0x000000),
GREEN(0x00FF00)
}
3. 枚举常量的匿名类
- 要实现枚举常量的匿名类,则必须提供一个抽象方法(必须重写的方法)。且该方法定义在枚举类内部。而且必须在枚举变量的后面。
- 枚举变量之间使用逗号(,)分割开。但是最后一个枚举变量必须使用分号结束。不然定义不了抽象方法。
- 在上面已经说过,每一个枚举常量就是一个对象。
enum class ConsoleColor(var argb : Int){
RED(0xFF0000){
override fun print() {
println("我是枚举常量 RED ")
}
},
WHITE(0xFFFFFF){
override fun print() {
println("我是枚举常量 WHITE ")
}
},
BLACK(0x000000){
override fun print() {
println("我是枚举常量 BLACK ")
}
},
GREEN(0x00FF00){
override fun print() {
println("我是枚举常量 GREEN ")
}
};
abstract fun print()
}
fun main(args: Array) {
ConsoleColor.BLACK.print()
}
输出结果:
我是枚举常量 BLACK
4. 枚举类的使用- 每个枚举常量都包含两个属性:name(枚举常量名)和ordinal(枚举常量位置)
- 提供了values()和valueOf()方法来检测指定的名称与枚举类中定义的任何枚举常量是否匹配。
- 自 Kotlin 1.1起,可以使用 enumValues()和 enumValueOf()函数以泛型的方式访问枚举类中的常量。
- 访问枚举变量属性
fun main(args: Array) {
println("name = " + Color.RED.name + "\tordinal = " + Color.RED.ordinal)
println("name = " + Color.WHITE.name + "\tordinal = " + Color.WHITE.ordinal)
println("name = " + Color.BLACK.name + "\tordinal = " + Color.BLACK.ordinal)
println("name = " + Color.GREEN.name + "\tordinal = " + Color.GREEN.ordinal)
}
enum class Color(var argb : Int){
RED(0xFF0000),
WHITE(0xFFFFFF),
BLACK(0x000000),
GREEN(0x00FF00)
}
输出结果:
name = RED ordinal = 0 name = WHITE ordinal = 1 name = BLACK ordinal = 2 name = GREEN ordinal = 3
- 使用
enumValues()
和enumValueOf()
访问
println(enumValues().joinToString { it.name })
println(enumValueOf("RED"))
输出结果:
RED, WHITE, BLACK, GREEN RED
- 使用
valueOf()
和values()
检测
println(Color.valueOf("RED"))
println(Color.values()[1])
println(Color.values()[2])
输出结果:
RED WHITE BLACK
5. 源码分析即Enum.kt
这个源文件。在这里我大致的说明一下这个源文件的方法、属性等。有兴趣的可以去看看这个源文件。其实里面也没几个方法。
public abstract class Enum(name: String, ordinal: Int): Comparable{
companion object {}
public final val name: String
public final val ordinal: Int
public override final fun compareTo(other: E): Int
protected final fun clone(): Any
public override final fun equals(other: Any?): Boolean
public override final fun hashCode(): Int
public override fun toString(): String}
默认实现了companion object {}
, 这也是我们访问枚举常量无需实例化枚举类的原因
仅提供了两个属性,即我们上面用到的枚举常量名称(name)和枚举常量位置(ordinal)
实现了Comparable
接口,这也是我们能获取枚举常量位置的原因