About Kotlin(2)
继续昨天的部分。介绍Kotlin中的类。
Kotlin中的类
抽象类和接口
抽象类
跟Java一样,使用abstract关键字
open class Base{
open fun f(){}
}
abstract class Derived:Base(){
override abstract fun f()
}
接口
//内部可以直接写实现
interface MyInterface{
fun bar()
fun foo(){ //默认实现
println("foo")
}
}
//接口中可以写属性。不允许初始化。实现类必须初始化
interface MyInterface2{
var name:String //抽象
}
class MyImpl:MyInterface2{
override var name:String="override name" //重载属性
}
密封类
使用sealed
修饰符修饰。其实是一组类的集合。可以用来表示受限的类的继承结构。
其也可以有子类,所有子类也必须在相同的文件中声明。
密封类从某种意义上说,它们是枚举类的扩展:枚举类型的值集也受到限制,但每个枚举常量仅作为单个实例存在,而密封类的子类可以包含多个实例并包含状态。这样又具备了枚举不具备的灵活性。
sealed class BaseClass {
class Test1 : BaseClass() {
override fun test() {
println("Test1实例")
}
}
class Test2 : BaseClass() {
override fun test() {
println("Test2实例")
}
}
object Test3 : BaseClass() {
override fun test() {
println("Test3实例")
}
}
open fun test() {
println("BaseClass实例")
}
}
fun test(instance: BaseClass)=when(instance){
is BaseClass.Test1-> instance.test()
is BaseClass.Test2-> instance.test()
is BaseClass.Test3->instance.test()
}
fun main(str: Array<String>) {
test( BaseClass.Test1() )
test( BaseClass.Test2() )
test( BaseClass.Test3 )
}
内部类
inner标记
使用inner
标记才能够访问外部类的变量
class Outer{
private val bar:Int = 1
inner class Inner{
fun foo()=bar
}
}
//调用的方式.和java类的内部类调用的方式相同
val demo = Outer().Inner().foo()
嵌套类
不用inner
标记,直接写在类的内部的类,在kotlin中称为所谓的嵌套类
class Outer{
private val bar: Int = 1
class Nested{
fun foo()=2
}
}
//嵌套类的调用有点像静态内部类。
val demo = Outer.Nested().foo()
枚举类
枚举类最基本的用法是实现类型安全的枚举
enum class Direction{
NORTH,SOUTH,WEST,EAST
}
//和Java一样,每个枚举类都是枚举的实例,可以被初始化
enum class Color(val rgb:Int){
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF)
}
匿名类
enum class ProtocolState{
WAITING{
override fun signal()=WAITING
},
TALKING{
override fun signal()=TALKING
};//这里需要用分号分割
abstract fun signal():ProtocolState
}
Object类(及匿名类)
在Kotlin中使用对象表达式和对象声明进行表示
对象表达式(匿名类)
匿名类其实就是在Java中的匿名内部类。
java中调用方法时,提供的匿名内部类
fun countClicks(window:JComponent){
var clickCount = 0
val enterCount=0
//通常的情况,使用Object开头就可以
window.addMouseListener(object:MouseAdapter()){
override fun mouseClicked(e:MouseEvent){
//与Java不同的是,甚至可以直接访问变量。(未被final修饰)!
clickCount++
enterCount++
}
...
}
}
//多个超类的情况
open class A(x:Int){
public open val y:Int=x
}
interface B{...}
val ab :A=object:A(1),B{
override val y = 15
}
//如果只是需要一个对象,什么都不需要的话。也可以直接写
fun foo(){
val adHoc = object{
var x:Int = 0
var y:Int =0
}
println(adHoc.x+adHoc.y)
}
这里有一点值得特别注意的的是:
匿名对象可以用作只在本地和私有作用域中声明的类型。只能做为私有函数的返回值。
class C{
//私有函数,所以其返回雷士的对象是匿名对象
private fun foo()=object{
val x :String="x"
}
//默认都是public final的方法.使用对象声明返回的类型是Any
fun publicFoo()=object{
val x:String="x"
}
fun bar(){
val x1= foo().x //可以直接访问
val x2= publicFoo().x //错误!未能解析的引用"x"
}
}
对象声明
单例
是指使用object关键字声明的一种类。这种类是单例,并且所有的成员都是静态方法。
object DataProviderManager{
fun registerDataProvider(provider:DataProvider){}
}
伴生对象
类内部的对象声明可以使用companion
关键字标记
class MyClass{
//就是静态内部类咯?但是每个类的伴生对象只能有一个!?
companion object Factory{
fun create():MyClass=MyClass()
}
}
//调用方式类似于Java中的静态方法
val instance = MyClass.create()
//如果按照下列写法,调用时,可以使用名称 Companion
class MyClass{
companion object{}
}
val x = MyClass.Companion
这里需要注意的是:
在 JVM 平台,只有使用 @JvmStatic 注解,才能将伴生对象的成员生成为真正的静态方法和字段。否则,都只是实例变量
//即使伴生对象的成员看起来像其他语言的静态成员,在运行时他们仍然是真实对象的实例成员,而且,例如还可以实现接口:
interface Factory<T> {
fun create(): T
}
class MyClass {
companion object : Factory<MyClass> {
//注意需要写Override
override fun create(): MyClass = MyClass()
}
}
//当然,在 JVM 平台,如果使用 @JvmStatic 注解,你可以将伴生对象的成员生成为真正的静态方法和字段。
//@JvmStatic 注解也可以应用于对象或伴生对象的属性, 使其 getter 和 setter 方法在该对象或包含该伴生对象的类中是静态成员。更多详细的内容之后再看
class MyClassJVM {
companion object : Factory<MyClassJVM> {
@JvmStatic override fun create(): MyClassJVM = MyClassJVM()
}
}
到这里,就大概把Kotin中的类汇总完了。接下来,也还是会按照参考文章的这个思路。记录Kotlin中的属性。方法。修饰符。