在前面几个章节中,详细的介绍了Kotlin
类的类别中的数据类
、密封类
、接口类
以及枚举类
。在这个章节中会对Koltin
的抽象类
和内部类
做出一个详细的讲解。若是对上面所提到的类的类别还不是很清晰的,请阅读个人前几篇文章。
Kotlin——中级篇(六):数据类(data)、密封类详解
Kotlin——中级篇(五):枚举类(Enum)、接口类(Interface)详解
Kotlin——中级篇(一):类(class)详解html
- 咱们知道,在实际的开发程序的时候,通常都会写一个基类,封装经常使用方法、以及处理一些共有的逻辑,可是程序逻辑是根据每一个类不一样的功能实现不一样的代码。而这个所谓的基类,通常都是一个抽象类。不论是
Java
仍是Kotlin
,实现其抽象类的做用就在于此。那么什么是抽象类呢,它是怎么定义的,它又要怎么使用呢?
抽象类,能够理解为类定义了一个模板。全部的子类都是根据这个模板是填充本身的代码。java
1.一、关键字git
- 声明一个抽象(类或函数)的关键字为:
abstract
其中值得注意的是:抽象能够分为抽象类、抽象函数、抽象属性。而一个抽象类和普通类的区别在于抽象类除了能够有其本身的属性、构造函数、方法等组成部分,还包含了抽象函数以及抽象属性。github
例:算法
abstract class Lanauage{ val TAG = this.javaClass.simpleName // 自身的属性 // 自身的函数 fun test() : Unit{ // exp } abstract var name : String // 抽象属性 abstract fun init() // 抽象方法 } /** * 抽象类Lanauage的实现类TestAbstarctA */ class TestAbstarctA : Lanauage(){ override var name: String get() = "Kotlin" set(value) {} override fun init() { println("我是$name") } } /** * 抽象类Lanauage的实现类TestAbstarctB */ class TestAbstarctB : Lanauage(){ override var name: String get() = "Java" set(value) {} override fun init() { println("我是$name") } } fun main(args: Array<String>) { // val lanauage = Lanauage() 是错误的,由于抽象类不能直接被实例化 val mTestAbstarctA = TestAbstarctA() val mTestAbstarctB = TestAbstarctB() println(mTestAbstarctA.name) mTestAbstarctA.init() println(mTestAbstarctB.name) mTestAbstarctB.init() }
输出结果为:json
Kotlin 我是Kotlin Java 我是Java
1.二、小结设计模式
- 抽象类自己具备普通类特性,以及组成部分。不过值得注意的是,抽象类不能直接被实例化
- 其抽象了类的子类必须所有重写带
abstract
修饰的属性和方法。- 抽象成员只有定义,没有实现。都有
abstract
修饰符修饰。- 抽象类是为其子类定义了一个模板。不一样是类实现不一样的功能
- 在
Kotlin
中的抽象类在顶层定义的时候只能使用public
可见性修饰符修饰。- 抽象类中能够定义内部抽象类。
- 只能继承一个抽象类。
- 若要实现抽象类的实例化,须要依靠子类采用向上转型的方式处理。
- 抽象类能够继承自一个继承类,即抽象类能够做为子类。不过,抽象类建议不用
open
修饰符修饰,由于能够覆写抽象类的父类的函数。
例:ide
open class Base{ open fun init(){} } abstract class Lanauage : Base(){ val TAG = this.javaClass.simpleName // 自身的属性 // 自身的函数 fun test() : Unit{ // exp } abstract var name : String // 抽象属性 abstract override fun init() // 覆写父类的方法 abstract class Name(){} // 嵌套抽象类,可查看第二节中的嵌套类使用 } fun main(args: Array<String>) { // 若要实现抽象类的实例化,须要依靠子类采用向上转型的方式处理。 val mLanauage : Lanauage = TestAbstarctB() }
- 在
Java
的设计模式中,有一种设计模式叫模板设计模式
,其定义为:
- 定义一个操做中算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类能够不改变算法的结构便可重定义该算法的某些特定步骤。
- 通俗点的理解就是 :完成一件事情,有固定的数个步骤,可是每一个步骤根据对象的不一样,而实现细节不一样;就能够在父类中定义一个完成该事情的总方法,按照完成事件须要的步骤去调用其每一个步骤的实现方法。每一个步骤的具体实现,由子类完成。
Kotlin
和Java
是互通的,说明Kotlin
也是支持这种设计模式的。
若是你对Java
中的模板设计模式不是很了解的,请参见这篇文章函数
在实际开发中,用到内部类的地方是不少的。好比说:工具
- 对于
Android
开发来讲,列表适配器(adapter
)中的ViewHolder
类,就是一个内部类。- 根据后台开发人员提供的
json
字符串生成的对象中,也包含另一个对象,这也是一个内部类。
上面提到的两种状况,是在开发中最多见的。固然,说到内部类,就必须世道另外一个概念嵌套类,所谓的嵌套类:即指一个类能够嵌套在其余类中。
例:
class Other{ // 外部类 val numOuther = 1 class Nested { // 嵌套类 fun init(){ println("执行了init方法") } } } fun main(args: Array<String>) { Other.Nested().init() // 调用格式为:外部类.嵌套类().嵌套类方法/属性 }
输出结果为:
执行了init方法
注意:
- 调用嵌套类的属性或方法的格式为:
外部类.嵌套类().嵌套类方法/属性。在调用的时候嵌套类是须要实例化的
。- 嵌套类不能使用外部类的属性和成员
在上面的例子中讲解了嵌套类的使用,而内部类和嵌套类仍是有必定的区别的,并且内部类是有特定的关键字去声明的。
声明一个内部类使用
inner
关键字。
声明格式:inner class 类名(参数){}
例:
class Other{ // 外部类 val numOther = 1 inner class InnerClass{ // 嵌套内部类 val name = "InnerClass" fun init(){ println("我是内部类") } } } fun main(args: Array<String>) { Other().InnerClass().init() // 调用格式为:外部类().内部类().内部类方法/属性 }
注意:
- 调用内部类的属性或方法的格式为:
外部类().内部类().内部类方法/属性。在调用的时候嵌套类是须要实例化的
。- 内部类不能使用外部类的属性和成员
做为一名
Android
开发者,对匿名内部类都不陌生,由于在开发中,匿名内部类随处可见。好比说Button
的OnClickListener
,ListView
的单击、长按事件等都用到了匿名内部类。
通常的使用方式为定义一个接口,在接口中定义一个方法。
例:
class Other{ lateinit private var listener : OnClickListener fun setOnClickListener(listener: OnClickListener){ this.listener = listener } fun testListener(){ listener.onItemClick("我是匿名内部类的测试方法") } } interface OnClickListener{ fun onItemClick(str : String) } fun main(args: Array<String>){ // 测试匿名内部类 val other = Other() other.setOnClickListener(object : OnClickListener{ override fun onItemClick(str: String) { // todo println(str) } }) other.testListener() }
输出结果为:
我是匿名内部类的测试方法
遗留的问题
在上面实现的匿名内部类是很常规的用法以及写法。在咱们的实际开发当中也是你们熟知的写法。可是在咱们实际开发当中,会引入
lambda
语法糖,让咱们的项目支持lambda
语法,简化代码量。在这里我也是想把用lambda
语法实现匿名内部类实现的代码贴出来,可是考虑到不少朋友不知道lambda
语法强大或者对lambda
不了解,同时考虑到篇幅缘由,故而在个人下一篇博文Kotlin——高级篇(一):Lambda表达式详解去讲解。
所谓局部类,这一点和
Java
是一致的。即定义在方法(函数)中的类。
例:
class Other{ // 外部类 val numOther = 1 fun partMethod(){ var name : String = "partMethod" class Part{ var numPart : Int = 2 fun test(){ name = "test" numPart = 5 println("我是局部类中的方法") } } val part = Part() println("name = $name \t numPart = " + part.numPart + "\t numOther = numOther") part.test() println("name = $name \t numPart = " + part.numPart + "\t numOther = numOther") } } fun main(args: Array<String>) { // 测试局部类 Other().partMethod() }
输出结果为:
name = partMethod numPart = 2 numOther = 1 我是局部类中的方法 name = test numPart = 5 numOther = 1
经过上面的实例:咱们能够看出:
- 局部类只能在定义该局部类的方法中使用。
- 定义在实例方法中的局部类能够访问外部类的全部变量和方法。但不能修改
- 局部类中的能够定义属性、方法。而且能够修改局部方法中的变量。
熟悉
Java
的朋友都知道Java
的静态类,或者说用static
修饰符修饰的类。可是在Kotlin
中,是不存在static
关键字的。那么咱们怎样去实现一个静态类呢?
关于静态类的使用,以及静态类的语法。以及Koltin
的单例模式实现。因为篇幅缘由我在这里就不展现了。有兴趣的朋友请参见kotlin中的object更像是语法糖。这篇文章是别的大牛诠释静态类以及单例实现很好的文章。后面我会出一篇详细的文章为你们讲解。
在学完本篇博文中,你应该掌握抽象类
的做用,掌握其和普通类
、接口类
、继承类
的区别所在,了解实现抽象类
的意义,或者说在项目中为何要用抽象类
去编写一个基类
等。
对于嵌套类
和内部类
而言,知道这二者的区别所在,和熟知他们在项目中用在什么地方就够了。对于静态类
来讲,经常使用的实现都是用其去实现一个单例模式。在Koltin
的不像Java
同样实现不少的工具类,由于Kotlin
中的扩展功能很强大。能够用扩展去替换掉大部分的工具类。本篇文章主要是展现object
的用法而已,详细的使用场景和用法会在后续的文章中为你们奉上。
若是各位大佬看了以后感受还阔以,就请各位大佬随便star
一下,您的关注是我最大的动力。
个人我的博客:Jetictors
个人github:Jetictors
个人掘金:Jetictors