從java到Kotlin學習三:類 對象 和接口

相比較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中能夠實現多個 

關於對象表達式 我們會在下一章具體說 這裏先跳過~


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章