[kotlin] class, object, interface -1

22450 ワード

kotlin in action을 보고 정리한 글입니다

ああ、勉強したくない。


コトリンのclass、interfaceはjavaといくつかの違いがあります.
たとえば、インタフェースには属性宣言があります.
つまりfinalとpublicはdefaultです.
Cottlinに新しく登場したdataclassにはdefaultメソッドがあり、既存のクラスメソッドを一つ一つ定義する手間を避けることができます.

Defining class hierarchies


重要な概念
  • sealed modifier
  • Interfaces in kotlin


    インタフェースにはabstractメソッド、non-astractメソッドを含めることができますが、ステータスを含めることはできません.
    interface Clickable {
      fun click()
    }
    上記のコードはabstract method clickを定義しています.
    英語での声明や実施で混乱する可能性があると思います.もし私たちがそれを指摘したら、
    上記のように、インタフェースの作成は宣言され、インタフェースを使用してclassを作成することを実装と呼びます.잘 구분하자
    class Button: Clickable {
      override fun click() = println("I was clicked")
    }
    >>> Button().click()
    // I was clicked
    Javaまたはjavascriptとは異なり、Cottlinはextends(インタフェースのタイプスクリプト)の代わりに:を使用し、構文を簡略化します.
    classは複数のインタフェースを実現することができ、extendsは最大1つのclassに対してjavaと同じである可能性がある.
    overrideはjavaの@Overrideコメントで、javaとは異なりkotlinはoverride修飾子を使用する必要があります.コットリンはこのような断言を採用し、Javaで発生する可能性のある意外なカバーを防止した.
    インタフェースメソッドはdefaultで実装できます.Java 8はdefault keywordを使用する必要がありますが、Cortlinではこのような注釈はありません.
    interface Clickable {
      fun click()
      fun showOff() = println("I'm clickable!")
    }
    ここでclick法をRegular method declarationと呼ぶ.
    showOffメソッドはmethod with a default implementationと呼ばれています.
    Clickableインタフェースを実装する場合、デフォルト実装のshowOffを使用する以外は、Clickに対して必要な実装を実行するだけでよい.もちろん、showOffでもカバーできます
    interface Focusable {
      fun setFocus(b: Boolean) = println("I ${if (b) "god" else "lost"}focus.")
      
      fun showOff() = println("I'm focusable!")
    }
    Buttonクラスでは、defaultインプリメンテーションが適用された2つのクラスと、適用されていない2つのクラスを同じメソッドで実装するとどうなりますか?この場合、明確に書き換えるべきです.次のエラーが表示されます.
    The class 'Button' must
    override public open fun showOff() because it inherits
    many implementations of it.
    class Button: Clickable, Focusable {
      override fun click() = println("I was clicked")
      
      override fun showOff() {
        super<Clickable>.showOff()
        super<Focusable>.showOff() 
      }
    }
    ここでshowOffメソッドは2つのインタフェースで同じなので、明示的に上書きする必要があります.インタフェースに適用されるdefault実装を継承するために、superキーワードが使用される.Javaと文法の違いを見てみましょう
    // java
    Clickable.super.showOff()
    // kotlin
    super<Clickable>.showOff()

    open, final, and abstract modifiers: final by default


    Javaでは、superclass付きfinalキーワードのメソッドはsubclassで上書きできません.ベースクラスのインプリメンテーションを変更すると、サブクラスは、これらのベースクラスが脆弱であると誤ってベースクラスのインプリメンテーションを推定します.superclassが書き換え可能な実装を詳細に説明していない場合、baseclassへの小さな変更は複数のコードで副作用を引き起こす可能性があります.
    design and document for inheritance or else prohibit it
    ; Joshua Bloch-Effective Javaの作者
    Javaでこれらの副作用を最小限に抑えるためには、subclassに上書きされたくない方法はfinal modifierを使用して強制しなければならない.
    kotlinはfinal modifierをdefaultとして使用し,このsie効果を最小化した.
    上書きを可能にするためにはopen修飾子を明確に使用する必要があります.
    open class RichButton: Clickable {
      fun disable() {}
      
      open fun animate() {}
      
      override fun click() {}
    }
    disableに加えて、animate、clickは他の関数で上書きできます.
    上書きする関数が他のインプリメンテーションでfinalである場合は、明確に指定する必要があります.
    open class RichButton: Clickable {
      final override fun click() {}
    }
    Javaと同様に、コトリンではabstract classで宣言されたabstract関数は常に他のclassで実装される必要があるため、open修飾子を追加する必要はありません.
    abstract class Animated {
     abstract fun animate()
     open fun stopAnimating() {}
     
     fun animateTwice() {}
     
    }
    ここでanimateはopen修飾子を追加する必要はありませんが、animateTwiceはoverrideのターゲットではありません.

    Visibility modifiers: public by default


    classのpropertiesの制御権を詳細に説明できる修飾子を可視修飾子と呼び、パッケージに使用します.
    コトリンのdefault visibility modifierはpublicです.
    コトリンにはinternalというvisibility modifierがあり、モジュール内部からしかアクセスできません.
    internal open class TalkativeButton: Focusable {
      private fun yell() = println("Hey!")
      protected fun whisper() = println("Let's talk!")
    }
    
    fun TalkativeButton.giveSpeech() {
      yell()
      
      whisper()
    }
    TalkativeButton.giveSpeechは公開されており、TalkativeButtonは内部声明である.less-bisibleタイプへの参照は禁止されているため、内部クラスTalkativeButtonをreferenceタイプとして使用して共通の拡張関数を作成することはできません.
    'public' member exposes its 'internal' receiver type TalkativeButton
    この問題を解決するには、giveSpeechを内部に設定するか、classを共通に設定する必要があります.
    Javaでは、同じパッケージ内から保護されたメンバーにアクセスできますが、コトリンでは不可能です.保護されたメンバーは、クラス内またはサブクラスにのみアクセスできます.

    Inner and nested classes: nested by default


    Javaのように、コトリンでもclass内部でclassを宣言することができます.違いは、cottinのnested classがoutherclassインスタンスにデフォルトでアクセスできないことです.
    interface State: Serializable
    
    interface View {
      fun getCurrentState(): State
      fun restoreState(state: State) {}
     
    JavaスタイルでViewを実現するButton classを実現しましょう
    public class Button implements View {
      @Override
      public State getCurrentState() {
        return new ButtonState();
      }
      
      @Override
      public void restoreState(State state) { /*...*/}
      
      public class ButtonState implements State { /*...*/ }
    }
    Stateインタフェースを用いてButtonクラス内部でButtonに関連する状態Button Stateを実現した.getCurrentStateを使用してステータスインスタンスを戻そうとしますが、java.io.NotSerializable- Exception: Buttonエラーが発生する可能性があります.Javaでは、classの内部で別のclassを定義するとdefaultが内部classになるため、ButtonState classがButton classを参照し、類似のエラーが発生します.
    コトリンではどうなるの?
    class Button: View {
      override fun getCurrentState(): State = ButtonState()
      
      override fun restoreState(state: State) {/*...*/}
      
      class ButtonState : State {/*...*/}
    }
    Cottlinでは、nested classはjavaのstatic nested classと同じです.Inner classのように動作するには、inner修飾子を明示的に追加する必要があります.

    Kotlin action p.76のFigure 4.1
    Nested classはouterclassの参照を持たず、inner classはouterclassの参照を持つ.
    cottlinにouterclassのreferenceを取得させるには、次の手順に従います.
    class Outer {
      inner class Inner {
        fun getOuterReference(): Outer = this@Outer  
      }
    }

    Sealed classes: defining restricted class hierarchies

    interface Expr
    class Num(val value: Int) : Expr
    class Sum(val left: Expr, val right: Expr) : Expr
    
    fun eval(e: Expr): Int =
      when (e) {
        is Num -> e.value
        is Sum -> eval(e.right) + eval(e.left)
        else ->
          throw IllegalArgumentException("Unknown expression")
      }
    when文を使用する場合、defaultオプションelseを同時に作成するのは不便です.また、subclassの作成時にfun evalを変更しないと、予期せぬエラーが発生する可能性があります.
    cottlinでは、superclassにsealed modifierを付けることで、コンパイラにsubclassを生成できないことを伝えることができます.
    sealed class Expr {
      class Num(val value: Int) : Expr()
      class Sum(val left: Expr, val right: Expr) : Expr()
    }
    すべてのシールクラスのsubclassをwhen文内で処理する場合は、default branchを作成する必要はありません.ちなみにsealed modifierにはopenが含まれているのでopen modifierを追加する必要はありません.sealedインタフェースはありません.
    内部では、Expr classはプライベートコンストラクション関数で構成され、class内部でのみ使用できます.