相比較java來說 沒有太大改變 我們一起來看下 這章節我不在粘java的例子了 但是 會做簡單總結 這樣大家能看的更明確一點
接口
java
public interface _Clickable {
void click();
}
public class _ClickAbleImpl implements _Clickable{
@Override
public void click() {
}
}
kotlin
kotlin 默認public 同時 能夠包含非抽象方法 但是 該方法必須被顯示實現 否則會報錯(kotlin 強制要求提供自己的實現)
class ClickableImpl:Clickable{
override fun click() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun getName():String {
super.getName()
}
}
kotlin使用 : 來代替 implements 和 extends 其他基本一致
修飾符
java
class 和 method 默認修飾符是 open 就是我們能夠爲該class 創建子類 並且重寫需要的方法 除非我們使用finial來修飾
kotlin
class和method 默認是close 就是默認使用finial修飾 如果想繼承和重寫 必須使用open 修飾 class和method 我們同樣 可以顯示的使用finial來禁止method被重寫
類中修飾符意義
finial : 不能被重寫 類中成員默認使用
open: 可以被重寫 需要顯示聲明
abstract : 必須被重寫
可見性修飾符
public private protected 這三個和java是一樣的
internal 只在模塊中可見(kotlin特有的)--模塊 即 一組一起編譯的文件 我理解就是model
內部類和嵌套類 (默認是嵌套類)
內部類 默認持有外部類對象的引用 嵌套類 不持有外部類對象的引用
這兩個是什麼意思呢 ?
java:
內部類: class B{...} 嵌套類:(靜態內部類): classB{...}
class A{...} static class A{...}
kotlin :
內部類 :class B{...} 嵌套類: class B{...}
inner class A{...} class A{....}
如果想從inner class 訪問 ouer class 那麼需要使用this@outer 來獲取外部類對象
密封類
kotlin 特有概念 能夠限制子類數量的 類
對於接口類 InterA 我們想 只要兩個子類 classA :InterA class _A :InterA 這時候我們就可以使用密封類 scale
scale class InterA{
classA :InterA {...}
class _A :InterA {...}
}
注:子類必須卸載接口類裏面(1.1中已經去掉了這個限制) 前面我們說過對於class 和method默認是close 不支持 繼 承和重寫 但是 scale 默認是open
類的聲明
前面我們已經說過繼承或者實現一個類 我們使用 :來替代implement 和 extends 那麼下面我們看下類的初始化以及聲明
主構造方法:
在kotlin中我們可以使用 class A constructor (val name:String) 來定義一個類 沒有任何方法體
這樣聲明就相當於java中 class A { public A(String name){}} 也就是後面加上() 就代表了我們的構造方法
這樣的構造方法稱爲主構造方法 constructor 可以省略 class A (val name:String)
我們看下 構造方法中的參數是怎麼工作的
class A(val name :String){
val _name:String
init{ _name=name} //初始化語句
}
construct :聲明構造方法 (無論主構造或者是從構造)
init :引入初始化塊 類被創建的時候執行
val:表示會被初始化value初始化
java:默認實現無參構造
kotlin : open class A 我們這樣定義一個類 表示該類只有一個無參構造方法 但是如果我們繼承該類 必須顯示調用A()
class B:A()
注意:kotlin 和java一樣 接口是沒有構造方法的 所以 實現接口不需要加()
多種構造方式
open class View{
constructor(ctx:Context){...}
constructor(ctx:Context,attr:Int){...}
}
上面的demo中沒有主構造方法 只有兩個從構造方法
我們來繼承下 該類
class MyView :View{
constructor (ctx:Context) :this(ctx,0)
constructor(ctx:Context,attr:Int):super(ctx:Context,attr:Int){}
}
這個是不是比較熟悉 我們java 自定義View中經常這麼寫 一個參的構造方法 委託當前類中兩個參的實現 兩個參的委託View中的默認實現
注:如果類沒有主構造方法 那麼每個從構造方法必須初始化 基類 或者委託給初始化了基類的構造方法
數據類:
java 中 我們通常需要手動實現 equals 和 toString
kotlin中 幫助我們實現了這些通用方法
data class User(val name :String,val age:Int)
注:數據類的參數類型 最好是val 雖然 var 也可以 但是很有可能在線程中 被修改值
爲了更方便val 的數據操作 kotlin 生成了一個方法 copy 這樣我們就可以手動修改值了
val Bob=User("Bob",0)
Bob.copy(age=18)
copy有單獨的生命週期 並不會影響原始實例的位置 很方便修改
手動實現copy
class User(val name :String,val age:Int){
...
fun copy(name:String=this.name,age:Int=this.age)=User(name,age)
}
委託類(by)
我們使用繼承實現某個類的時候 必須實現裏面所有的抽象方法 但是很多方式我們根本不需要 或者是完全可以使用默認實現 我們只想修改我們需要的就好了 那麼我們看下 demo
class DelegationCollection(innerList:ArrayList<SimpleDemoUtils.User>) :Collection<SimpleDemoUtils.User> {
override val size: Int
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
override fun contains(element: SimpleDemoUtils.User): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun containsAll(elements: Collection<SimpleDemoUtils.User>): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun isEmpty(): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun iterator(): Iterator<SimpleDemoUtils.User> {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}}
害怕 我們看下 使用委託 之後 世界都安靜了 爲什麼不用實現了呢 因爲我們將實現 全部委託給了 innerList 而innerList是ArrayList 本身就已經繼承自 Collection 實現了所有抽象方法了
class DelegationCollection(innerList: ArrayList<SimpleDemoUtils.User>) : Collection<SimpleDemoUtils.User> by innerList {}
那麼我們只需要修改我們需要的就好了 我們寫個完成的demo
/**
* @author zhangyanjiao
* @desc 我們想統計下 add 進來的元素個數
* hash 過濾重複元素 所以添加個數 和 真正添加進去的個數不完全相同 ok 我們測下
*/
class DelegationCollection<T>(val innerList:MutableCollection<T> = HashSet()) : MutableCollection<T> by innerList {
var addCount: Int = 0
override fun add(element: T): Boolean {
addCount++
return innerList.add(element)
}
override fun addAll(elements: Collection<T>): Boolean {
addCount += elements.size
return innerList.addAll(elements)
}
}
class ClickableImpl:Clickable{
override fun click() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun getName():String {
super.getName()
}
}
class ClickableImpl:Clickable{
override fun click() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun getName():String {
super.getName()
}
}
private fun delegation() {
val map = DelegationCollection<Int>()
map.addAll(listOf(1, 1, 2, 3))
Log.d("SecondActivity", "add count=${map.addCount},remain count =${map.size}")
}
結果 interface Clickable {
fun click()
fun getName():String="Clickable "
}
D/SecondActivity: add count=4,remain count =3
object 關鍵字
使用場景
- 對象聲明 是定義單例的一種方式
- 伴生對象可以支持工廠和其他與這個類相關 但調用時並不依賴實例的方法 成員可以通過類名來訪問
- 對象表達式 用來替代java的匿名內部類
單例 實現
object MyUtils{
fun add(a:Int,b:Int){
return a+b
}
}
調用方式:
MyUtils.add(1,2)
伴生對象(工廠方法 和靜態成員 的實現)
kotlin 不能擁有靜態成員,但是之前我們說頂層函數和成員 相當於靜態來使用 但是頂層函數不能訪問類的私有成員 。(也就是私有成員不能再類外部的頂層函數中使用)
那麼此時我們就可以用工廠方法來解決
companion :標記對象 可以直接通過容器名直接訪問這個對象的方法和屬性 不需要顯示制定對象名稱(很像static 方法調用)
class A{
companion object{
fun foo(){
...
}
}
}
調用
A.foo()
使用工廠方法代替從構造方法
class User(val name:String){
companion object{
fun newSubUserScribing(email:String){
return User(email)
}
}
}
對象表達式:匿名內部類
java
class A{
btView.setOnclickListener(new OnClickListener(){
...})
}
kotlin
class A{
btView.setOnclickListener(object:OnclickListener(){...})
}
使用object聲明並創建了一個實例 但是該實例並沒有名稱 只是實現OnCLickListener 在java中 匿名內部類 只能實現一個接口 但是kotlin中能夠實現多個
關於對象表達式 我們會在下一章具體說 這裏先跳過~