#8 kotlin classとinterfaces

10500 ワード

kotlinは宣言クラスがswiftよりも簡潔である
// swift
class Dog {
  //  
  var name: String
  var weight: Int
  
  init(name: String, weight: Int) {
    self.name = name
    self.weight = weight
  }
}

Kotlinの書き方、直接プロパティをコンストラクタに定義する
// kotlin
class Dog(val name: String, var weight: Int) {}

//  
class Dog(name: String, weight: Int) {
  val name = name
  var weight = weight
}

また、コンストラクタではval | varを使用して属性を定義する必要があります.valで定義された属性は、付与後は変更できません.すなわち、属性は読み取り専用です.
var dog = Dog("Lisa", 20)
dog.weight = 30 // weight   var   
dog.name = "Doge" // Error   val   

イニシャルブロック


他の言語とは異なり、オブジェクト構造(constructor)が完了した後、データのロードなどの複雑な操作をしたい場合は、initを使用して追加の操作を実行できます.
class Dog(val name: String, var weight: Int) {
  //   init blocks
  //  
  init {
    println("the first init block")
  }
  
  init {
    println("the second init block")
  }
}

Getter and Setter


クラスの各var宣言を使用するプロパティには、デフォルトでgetterとsetterが割り当てられていますが、val宣言を使用するプロパティは、1つのgetterにのみ与えられます.
var someProperty: String
    get() = field
    set(value) {
    field = value
    }

val readOnlyProperty: String
    get() = field

例:
// swift
class Point {
  var x = 0.0, y = 0.0
}
class Size {
  var width = 0.0, height = 0.0
}
class Rect {
  var origin = Point()
  var size = Size()
  
  var center: Point {
    get {
      let centerX = origin.x + (size.width / 2)
      let centerY = origin.y + (size.height / 2)
      return Point(centerX, centerY)
    }
    set(newCenter) {
        //      
      origin.x = newCenter - (size.width / 2)
      origin.y = newCenter - (size.height / 2)
    }
  }
}

kotlinバージョン:
// kotlin
class Point(var x: Double = 0.0, var y: Double = 0.0) {}
class Size(var width: Double = 0.0, var height: Double = 0.0) {}

class Rect(var origin: Point = Point(), var size: Size = Size()) {
  var center: Point
    get() {
      val centerX = origin.x + (size.width / 2)
      val centerY = origin.y + (size.height / 2)
      return Point(centerX, centerY)
    }
    set(value) {
        //      
      origin.x = value - (size.width / 2)
      origin.y = value - (size.height / 2)
    }
}

別の例:
// kotlin
class Dog(val name: String, var weight_param: Int) {
  var weight = weight_param
    set(value) {
      //   field  
      if (value > 0) field = value
    }
    
  var weightInKgs: Double
    //  get   body   =
    get() = weight / 2.2
}

次のようになります.
  • setterのfieldは、前方参照属性
  • を表す.

    クラスの継承


    他の言語と通じないところ
  • 子クラスが継承する場合、親クラスは構造
  • を完了する必要がある.
    この感覚は少し変で、他の言語と少し違います.swiftで例を挙げます.
    // Swift
    //  
    class Car {
      let make: Int
      let model: String
      
      init(make: Int, model: String) {
        self.make = make
        self.model = model
      }
      
      func move() {
        print("A car is moving")
      }
    }
    
    //    
    class ConvertibleCar: Car {
      override func move() {
        print("A convertible car is moving")
      }
    }
    
    let myCar = COnvertibleCar(make: 1990, model: "WorksWagen")
    myCar.move()
    

    kotlinでは、
    // kotlin
    open class Car(open val make: Int, open val model: String) {
      open fun move() {
        println("a car is moving")
      }
    }
    
    //  
    class ConvertibleCar(override val make: Int, override val model: String): Car(make, model) {
      override fun move() {
        println("a convertible car is moving")
      }
    } 
    
    val myCar = ConvertibleCar(1990, "WorksWagen")
    myCar.move()
    

    kotlinコンストラクタのパラメータのため、実際には属性は、継承時に親の属性の初期化が完了していることを確認します(個人的には書き方が少し違和感があります)
  • アクセス修飾子
  • kotlinのクラスと属性は、デフォルトの修飾子がfinalであり、継承され、属性がoverrideになりたい場合は、修飾修飾修飾子をopenに変更する必要があります.
    // kotlin
    
    // Car    open     final
    // make, model   override,   open 
    open class Car(open val make: Int, open val model: String) {
    
        //   override  
        fun bark() {
        println("bark ...")
        }
        
      open fun move() {
        println("a car is moving")
      }
    }
    
    // 
    class ConvertibleCar(override val make: Int, override val model: String): Car(make, model) {
      override fun move() {
        println("a convertible car is moving")
      }
    } 
    
    val myCar = ConvertibleCar(1990, "WorksWagen")
    myCar.move()
    
  • varおよびval修飾属性
  • 継承関係では、親クラスでvalで宣言された属性を使用し、変更が必要な場合はoverrideのキーワードを使用し、varで修飾された属性を使用する場合はinit blockで変更できます.
    // val  
    open class Car(open val make: Int, open val model: String) {
    
        open val image = "" //  
        
        fun bark() {
        println("bark ...")
        }
        
      open fun move() {
        println("a car is moving")
      }
    }
    class ConvertibleCar(override val make: Int, override val model: String): Car(make, model) {
    
        //  override 
        override val image: String = "convertibleCar.jpg"
      override fun move() {
        println("a convertible car is moving")
      }
    } 
    
    //  var  
    open class Car(open val make: Int, open val model: String) {
    
        // open  
        var image = "" //  
        
        fun bark() {
        println("bark ...")
        }
        
      open fun move() {
        println("a car is moving")
      }
    }
    class ConvertibleCar(override val make: Int, override val model: String): Car(make, model) {
    
        //   initializer block  
        init {
          image = "convertibleCar.jpg"
        }
      override fun move() {
        println("a convertible car is moving")
      }
    } 
    

    また、親クラスではvalで宣言された属性を使用し、子クラスではvarでoverrideを行うことができる.ただし、親にはvarで宣言された属性が使用され、子にはvalでoverrideを使用できません.
    open class Animal {
      open val name: String = ""
    }
    class Dog: Animal() {
      //   var  name  
      //  setter  
      override var name = "lily"
    }
    

    抽象クラス


    1つのクラスがabstractを使用する抽象クラスとして宣言する場合、openを使用して修飾する必要はない.
    abstract class Animal {}
    

    kotlinの抽象クラスは他の言語と基本的に類似しており、抽象クラスは抽象属性と抽象方法を持つことができ、サブクラスは抽象クラスで定義された抽象属性と方法を実現しなければならない.
    abstract class Animal {
      abstract val image: String
      abstract val food: String  
      var hunger = 10
      
      abstract fun makeNoise()
      abstract fun eat()
      
      open fun roam() {
        println("animal is roaming")
      }
      
      fun sleep() {
        println("animal is sleeping")
      }
    }
    
    //  
    abstract class Canine: Animal() {
      override fun roam() {
        println("the canine is roaming)
      }
    }
    
    //  
    //  
    class Wolf: Canine() {
      override val image = "wolf.jpg"
      override val food = "meat"
      
      override fun makeNoise() {
        println("Hooowwwl")
      }
      
      override fun eat() {
        println("the wolf is eating $food")
      }
    }
    

    インタフェース


    kotlinは他の言語と同様に1つのクラスしか継承できませんが、複数のインタフェースを実現できます.
  • 一般書き方
  • interfaceのキーワードを使用して、実装を与えることができて、実装を与えないことができます
    //  ,  
    interface IFlyable {
      fun fly()
    }
    
    //  
    //   override  
    interface IFlyable {
      fun fly() {
        println("I can fly")
      }
    }
    
  • Getter & setter

  • インタフェースにはプロパティも定義できます.プロパティはget()で値を返すことができます.インタフェースにコンストラクタがないため、直接値を初期化することはできません.
    //  
    interface IFlyable {
      fun fly()
      
      // error: Property initializers are not allowed in interfaces
      val velocity: Int = 20
    }
    
    //  
    interface IFlyable {
      fun fly()
      
      //  val  var
      val velocity: Int
        get() = 20
    }
    
    setterでは、インタフェースに後方参照フィールドが存在しないため、fieldでは使用できません.
    //  
    interface IFlyable {
      fun fly()
      
        // error: Property in an interface cannot have a backing field
      var velocity: Int
        get() = 20
        set(value) {
          if value > 0 {
            field = value
          }
        }
    }
    
    //  
    interface IFlyable {
      fun fly()
      
        //  var  val   setter
      var velocity: Int
        get() = 20
        set(value) {
          if value > 0 {
            //   field    
            print("your value is greater than 0")
          }
        }
    }
    

    is & as & when

  • isはあるタイプかどうかを判断するために用いる、!isはこれとは逆(この書き方を初めて見た)
    abstract class Animal {
      abstract val food: String
      
      fun eat() {
        println("animal is eating $food")
      }
    }
    
    class Dog: Animal() {
      override val food = "meat"
      
      fun bark() {
        println("a dog is barking")
      }
    }
    
    var a = Dog()
    
    if (a is Dog) {
      a.bark() 
    }
    
  • である.
  • as:タイプ変換に使用する、isはインテリジェント変換を実行するが、インテリジェント変換が失敗する場合があり、asを使用して明示的な変換を行う必要がある
    interface IRunable {
      fun run()
    }
    
    abstract class Animal: IRunable {
      abstract val food: String
      
      fun eat() {
        println("animal is eating $food")
      }
      
      override fun run() {
        println("some animal can run")
      }
    }
    
    class Dog: Animal() {
      override val food = "meat"
      
      fun bark() {
        println("a dog is barking")
      }
    }
    
    class Ground {
      //  var    something 
      var something: IRunable = Dog()
      
      fun showInfo() {
          //    
          // Smart cast to 'Dog' is impossible because 'something' is a mutable property that
          // could hae been changed by this time
        if (something is Dog) {
          something.bark()
        }
      }
    }
    
    //  ,  as  
    class Ground {
      //  var    something 
      var something: IRunable = Dog()
      
      fun showInfo() {
        if (something is Dog) {
          (something as Dog).bark() //  
        }
      }
    }
    
  • .
  • when:これが他の言語のswitch...case
    //  1  
    var temperature = 30
    var isCool: Boolean = when {
      temperature > 28 -> false
      else -> true
    }
    
    //  2   is  
    when (animal) {
      is Dog -> {
        // ...
      }
      is Cat -> {
        // ...
      }
    }
    
  • です.
    大まかな内容:
  • クラスの定義
  • 初期化ブロック
  • getterとsetter(fieldキーワード)
  • クラスの継承
  • 注意修飾子の使用open | final
  • 抽象クラス
  • var & val属性の違いを修飾し、overrideの場合は注意が必要であり、init blockの使用
  • もある.
  • インタフェースの使用
  • は、デフォルトのインプリメンテーションまたは抽象的な
  • を提供することができる.
  • はgetterとsetterを使用することができるが、setterではfield
  • は使用できない.
  • 補助論理キーワード
  • is & !is
  • as
  • when