enum class Direction
{
NORTH,SOUTH,WEST,EAST
}
使用
//定义一个枚举类变量
var direction : Direction
// 定义一个枚举类变量, 并初始化
var direction2 : Direction = Direction.NORTH
//未指定数据类型, 通过右侧的赋值自动检测类型
var direction3 = Direction.SOUTH
var direction4 = Direction.WEST
if(direction3 == direction4)
{
println("枚举类型值相等")
}else{
println("枚举类型值 bu 相等")
}
//引用枚举类中的值, 需要加上枚举类名
println(Direction.WEST)
enum class Direction private constructor(val d : Int)
{
NORTH(1),SOUTH(2),WEST(3),EAST(4);
override fun toString(): String {
return d.toString()
}
}
// 定义一个枚举类变量, 并初始化
var direction2 : Direction = Direction.NORTH
//获取枚举值名称和索引
println(direction2.name)
println(direction2.ordinal)
//通过valueOf方法传入枚举值名称来获取枚举值对应的数值
println(Direction.valueOf("WEST"))
for (d in Direction.values()){
println(d)
}
/**
* 对原生集合类MutableList扩展,让该类有交换任意两个集合元素位置的能力
*/
fun MutableList<Int>.swap(index1 : Int,index2 : Int)
{
val temp = this[index1];
this[index1] = this[index2];
this[index2] = temp
}
/**
* 为集合类ArrayList添加一个swap方法
*/
fun ArrayList<Int>.swap(index1 : Int,index2 : Int)
{
val temp = this[index1]
this[index1] = this[index2]
this[index2] = temp
}
open class Parent(val value1 : Int ,val value2 : Int)
{
var mValue1 : Int = value1
var mValue2 : Int = value2
fun add() : Int
{
return mValue1 + mValue2
}
}
class Child (value1 : Int,value2 : Int):Parent(value1,value2)
{
fun sub() : Int
{
return mValue1 - mValue2
}
}
/**
* 通过扩展向Parent类添加一个printResult方法
*/
fun Parent.printResult()
{
println("${mValue1} + ${mValue2} = ${add()}")
}
/**
* 通过扩展向Child类添加一个printResult方法
*/
fun Child.printResult()
{
println("${value1} - ${value2} = ${sub()}")
}
尽管parent2的实例是Child,但由于通过扩展向Child添加的printResult方法并没有重写Parent.printResult方法,因此parent2.printResult仍然调用的是Parent.printResult方法,因为open不能用子啊顶层函数中, 所以通过扩展是不能添加可继承的成员函数的(Kt默认不允许继承)。如果要让printResult函数可继承,那么可以将该函数放在Parent类中
open class Parent(val value1 : Int ,val value2 : Int)
{
var mValue1 : Int = value1
var mValue2 : Int = value2
fun add() : Int
{
return mValue1 + mValue2
}
open fun printResult()
{
println("${mValue1} + ${mValue2} = ${add()}")
}
}
class Child (value1 : Int,value2 : Int):Parent(value1,value2)
{
fun sub() : Int
{
return mValue1 - mValue2
}
override fun printResult()
{
println("${mValue1} - ${mValue2} = ${sub()}")
}
}
/**
* 通过扩展向Parent类添加一个printResult方法
*/
fun Parent.printResult()
{
println("${mValue1} + ${mValue2} = ${add()}")
}
/**
* 通过扩展向Child类添加一个printResult方法
*/
fun Child.printResult()
{
println("${value1} - ${value2} = ${sub()}")
}
运行结果
如果通过扩展向类中添加的成员函数与类中原来的成员函数的结构完全相同,那么哪个优先呢?MyClass类中有一个newInstance函数,现在使用扩展为MyClass类再添加一个相同的newInstance函数,函数的结构相同,但实现代码不同:
class MyClass
{
private var strValue:String = ""
constructor()
{
}
private constructor(str : String)
{
strValue = str
}
override fun toString(): String {
return strValue
}
fun newInstance(value : Int) : MyClass
{
return MyClass("内部成员函数")
}
}
/**
* 向MyClass类中添加一个newInstance函数, 与原来的相同
*/
fun MyClass.newInstance(value : Int):MyClass
{
return MyClass()
}
运行:
println(MyClass().newInstance(20))
结果:
明显,如果类内部的成员函数和通过扩展添加的成员函数冲突,那么内部成员函数的优先级更高,因此,通过扩展法务覆盖内部成员函数。
扩展属性和扩展函数类似,Kt属性在类中必须初始化,而初始化需要使用backing field, 也就是那个filed字段,可以将属性设置的值保存在field中,也可以从field获取属性值, 不过,通过扩展添加的属性是没有backing field的, 因此,扩展属性需要实现setter,才能为扩展属性初始化
class ExParaClass {
// 需要声明为public 或不加修饰符(默认为public) 否则扩展属性无法访问该变量
var mValue: Int = 0
//内部属性
var str: String = ""
get() = field
set(value) {
field = value
}
}
扩展属性:
//扩展属性 需要实现setter部分
var ExParaClass.value: Int
get() = mValue
set(value) {
mValue = value
}
执行:
var exParaClass = ExParaClass()
exParaClass.str = "hello"
exParaClass.value = 400 // 设置扩展属性的值
println(exParaClass.str)
println(exParaClass.value) //输出扩展属性的值
结果:
由于扩展属性没有backing field字段,因此保存和获取属性值, 需要使用一个类成员变量,但成员变量需要声明public, 否则扩展属性无法访问。
如果类中有伴随对象, 那么可以利用扩展为伴随对象添加成员
class MyClass
{
companion object { }
}
fun MyClass.Companion.test()
{
println("这是伴随对象成员函数")
}
运行
MyClass.test() //与调用静态成员函数一样,不需要使用类的实例
前面讲解的扩展代码都是写在顶层的,其实,扩展也可以在类中定义
class D
{
fun bar()
{
println("D . bar")
}
}
class C
{
fun baz()
{
println("C . bar")
}
//在C类中扩展D类
fun D.foo()
{
bar() //调用D类中的bar方法
baz() //调用C类中的baz方法
}
fun caller(d : D)
{
d.foo() // 调用扩展方法
}
}
执行
C().caller(D())
如果在D类中扩展C类,那么在D类扩展方法中调用C类和D类都有的成员函数(如 toString),那么到底是调用C类的成员函数,还是D类的成员函数?
class D
{
override fun toString(): String {
return "D 类"
}
}
class C
{
fun D.foo()
{
println(toString()) //调用D.toString()
println(this@C.toString()) //调用C.toString()
}
fun process(d : D)
{
d.foo()
}
override fun toString(): String {
return "C 类"
}
}
运行
C().process(D())
执行结果:
很明显,在D.foo函数中调用toString函数,会调用D.toString ,如果想在D.foo函数中调用C类的foo函数,需要使用[email protected]()
attention :
在C类中扩展D类,只能在C类中访问扩展的D类成员,不能在外部访问在C类中扩展的D类成员。比如:
D().foo()
写在顶层的扩展成员不能被继承, 因为无法添加open关键字, 但是在类中对另外一个类扩展却可以添加open关键字。
open class A
{
}
class A1 : A()
{
}
open class B
{
open fun A.foo()
{
println("A.foo in B")
}
open fun A1.foo()
{
println("A1.foo in B")
}
fun caller(a : A)
{
a.foo() //调用扩展函数
}
}
class B1 : B()
{
override fun A.foo()
{
println("A.foo in B1")
}
override fun A1.foo()
{
println("A1.foo in B1")
}
}
运行:
B().caller(A())
B1().caller(A())
B().caller(A1())
执行结果:
在B类中通过扩展向A类和A1类添加扩展时都加了open关键字,并且在B1类中,通过扩展重写了A类和A1类中的foo方法。