Kotlin core programming (7)

Kotlin core programming (7)

Article directory

  • Kotlin core programming (7)
    • multiple inheritance problem
      • Interface Implementation Multiple Inheritance Problem
      • getters and setters
      • Inner classes solve multiple inheritance problems
        • Inner and nested classes
      • Use delegation instead of multiple inheritance
    • data class
    • Pair and Triple
    • Data class conventions and uses

Multiple inheritance problem

Interface implements multiple inheritance issues

interface Flyer{<!-- -->
    fun fly()
    fun kind()= "flying animals Flyer"
}
interface Animal{<!-- -->
    val name: String
    fun eat()
    fun kind()="fly animals Animal"
}
class Bird(override val name: String):Flyer,Animal{<!-- -->
    override fun fly() {<!-- -->
        println("i am fly")
    }

    override fun kind() = super<Flyer>.kind() // super keyword, we
    // You can use it to specify which method to inherit from,

    override fun eat() {<!-- -->
        println("i am eating")
    }

}
fun main(args:Array<String>){<!-- -->
    val bird = Bird("sparrow")
    println(bird. kind())
}

//===========================================
interface Flyer{<!-- -->
    fun fly()
    fun kind()= "flying animals Flyer"
}
interface Animal{<!-- -->
    val name: String
    fun eat()
    fun kind()="fly animals Animal"
}
class Bird(override val name: String):Flyer,Animal{<!-- -->
    override fun fly() {<!-- -->
        println("i am fly")
    }

    override fun kind() = "a flying $name" /*. Of course, we can also take the initiative to implement the method,
    Overrides the connection method. */

    override fun eat() {<!-- -->
        println("i am eating")
    }

}
fun main(args:Array<String>){<!-- -->
    val bird = Bird("sparrow")
    println(bird. kind())
}
/*
1) When implementing an interface in Kotlin, it is necessary to implement the interface that has no default implementation
For methods and uninitialized properties, if multiple interfaces are implemented at the same time, the indirects will have the same value
When using the default implementation of the method name, you need to actively specify which interface method to use or override it.
Law;
2) If it is the default connection method, you can pass it in the implementation class
"super<T>" This method invokes it, where T is the name of the interface that owns the method;
3) When implementing the connected properties and methods, the override keyword must be included, not
Can be omitted. */

/*
The constructor parameter declared by val actually defines a property with the same name inside the class, so of course we
You can also put the definition of name inside the Bird class
*/
class Bird(name: String):Flyer,Animal{<!-- -->
   
    override val name : String // override cannot be less
    init {<!-- -->
        this.name=name
    }

    override fun fly() {<!-- -->
        println("i am fly")
    }

    override fun kind() = "a flying $name" /*. Of course, we can also take the initiative to implement the method,
    Overrides the connection method. */

    override fun eat() {<!-- -->
        println("i am eating")
    }
}
// You can also use the get method to initialize the name
override val name: String
        get() = name

getters and setters

When you declare the properties of a class, you should know that the Kotlin compiler also creates getter and setter methods for you behind the scenes. Of course, you can also actively declare these two methods to implement some special logic. There are two more points to note:

  1. The property declared by ?val will have only getter? method, because it cannot be modified; the property modified by var will have both getter and setter? method.
  2. The compiler will omit the getter and setter methods for properties modified by private, because they cannot be accessed outside the class, and the existence of these two methods is meaningless.

Inner classes solve multiple inheritance problems

class OuterKotlin{<!-- -->
    val name = "This is not Kotlin's inner class syntax"
    class ErrorInnerKotlin{<!-- --> // This is a nested class
        fun printName(){<!-- -->
            println("this name is $name") //Unresolved reference: name
        }
    }
}
/*
What we are currently declaring is not an inner class in Kotlin, but the syntax of a nested class.
If we want to declare an inner class in Kotlin, we must add an inner keyword before the class, like this: */
class OuterKotlin{<!-- -->
    val name = "This is not Kotlin's inner class syntax"
    inner class InnerKotlin{<!-- --> // This is the nested class
        fun printName(){<!-- -->
            println("this name is $name")
        }
    }
}

Inner and nested classes

/*
* Kotlin is the opposite way of thinking, the default is a nested class, you must add the inner keyword to be an inner class,
* That is to say, static inner classes can be regarded as nested classes.
* There is an obvious difference between an inner class and a nested class, which is specifically reflected in: the inner class contains a reference to its outer class instance, in the inner class we can use the attributes in the outer class,
*? As in the example above, the name attribute; the nested class does not contain a reference to its outer class instance, so it cannot call the properties of its outer class. */
/*We use the following example to implement multiple inheritance of internal classes, mainly because a horse and a donkey give birth to a donkey*/
open class Horse{<!-- --> //Mom
    fun runFast(){<!-- -->
        println("I can run fast")
    }
}
open class Donkey{<!-- --> // donkey
    fun doLongTimeThing(){<!-- -->
        println("I can do some thing long time")
    }
}
class Mule{<!-- --> // mule
    fun runFast(){<!-- -->
        HorseC(). runFast()
    }
    fun doLongTimeThing(){<!-- -->
        DonkeyC().doLongTimeThing()
    }
    private inner class HorseC:Horse()
    private inner class DonkeyC: Donkey()
}
/*
1. We can define multiple internal classes within a class, and each instance of the internal class has a unique independent state, which is independent of the information of the external object;
2. By letting the inner classes HorseC and DonkeyC respectively inherit the two outer classes Horse and Donkey, we can define their instance objects in the Mule class,
Obtained different states and behaviors of Horse and Donkey from it;
3. We can use private to modify the internal class, so that other classes cannot access the internal class, which has a very good encapsulation. */

Use ?delegate instead of multiple inheritance

/*Simply speaking, delegation is a special type, which is different from legal event delegation.
If you call methodA of class A, in fact, methodA of class B executes it behind the scenes.
 We only need to use the by keyword to achieve the effect of delegation. ?As we mentioned before by lazy syntax,
 In fact, it is the lazy initialization syntax implemented by the delegate. */
interface CanFly{<!-- -->
    fun fly()
}
interface CanEat{<!-- -->
    fun eat()
}
open class Flyer1 : CanFly{<!-- -->
    override fun fly() {<!-- -->
        println("I can fly")
    }
}
open class Animal1 : CanEat{<!-- -->
    override fun eat() {<!-- -->
        println("I can eat")
    }
}
class Bird1(fly:Flyer1,animal: Animal1):CanFly by fly,CanEat by animal{<!-- -->}
fun main(){<!-- -->
    val fly = Flyer1()
    val animal = Animal1()
    val b = Bird1(fly,animal)
    b. fly()
    b. eat()
}
/*
* 1. As mentioned above, the connection is in a state, so even if it provides a default method, the implementation is very simple, and complex logic cannot be implemented.
* It is also not recommended to implement complex method logic in interfaces. We can take advantage of this form of entrustment, although it is also an entrustment,
* But it is a concrete class to implement method logic, which can have stronger capabilities.
* 2. Assume that the class we need to inherit is A, and the entrusted objects are B and C. When we specifically adjust? It is not like a combination of A.B.method,
* ?It can directly adjust?A.method, which can better express the ability of A to own the method,
* It is more intuitive, although the specific method logic is implemented through the delegate object behind it. */

Data class

// define data class
data class Bird2(var weight:Double, var age:Int, var color: String)
// Compile into Java code
public final class Bird2 {<!-- -->
   private double weight;
   private int age;
   @NotNull
   private String color;

   public final double getWeight() {<!-- -->
      return this. weight;
   }

   public final void setWeight(double var1) {<!-- -->
      this.weight = var1;
   }

   public final int getAge() {<!-- -->
      return this. age;
   }

   public final void setAge(int var1) {<!-- -->
      this.age = var1;
   }

   @NotNull
   public final String getColor() {<!-- -->
      return this.color;
   }

   public final void setColor(@NotNull String var1) {<!-- -->
      Intrinsics. checkNotNullParameter(var1, "<set-?>");
      this.color = var1;
   }

   public Bird2(double weight, int age, @NotNull String color) {<!-- -->
      Intrinsics. checkNotNullParameter(color, "color");
      super();
      this.weight = weight;
      this. age = age;
      this.color = color;
   }

   public final double component1() {<!-- -->
      return this.weight;
   }

   public final int component2() {<!-- -->
      return this. age;
   }

   @NotNull
   public final String component3() {<!-- -->
      return this.color;
   }

   @NotNull
   public final Bird2 copy(double weight, int age, @NotNull String color) {<!-- -->
      Intrinsics. checkNotNullParameter(color, "color");
      return new Bird2(weight, age, color);
       /*
       The main function of the copy? method is to help us copy a new data class object from an existing data class object.
       In the process of copy execution, if you do not specify the value of the specific attribute,
Then the attribute value of the newly formed object will be the attribute value of the copied object,
This is what we usually call a shallow copy*/
   }

   // $FF: synthetic method
   public static Bird2 copy$default(Bird2 var0, double var1, int var3, String var4, int var5, Object var6) {<!-- -->
      if ((var5 & 1) != 0) {<!-- -->
         var1 = var0.weight;
      }

      if ((var5 & 2) != 0) {<!-- -->
         var3 = var0. age;
      }

      if ((var5 & 4) != 0) {<!-- -->
         var4 = var0. color;
      }

      return var0.copy(var1, var3, var4);
   }

   @NotNull
   public String toString() {<!-- -->
      return "Bird2(weight=" + this.weight + ", age=" + this.age + ", color=" + this.color + ")";
   }

   public int hashCode() {<!-- -->
      int var10000 = (Double. hashCode(this. weight) * 31 + Integer. hashCode(this. age)) * 31;
      String var10001 = this. color;
      return var10000 + (var10001 != null ? var10001. hashCode() : 0);
   }

   public boolean equals(@Nullable Object var1) {<!-- -->
      if (this != var1) {<!-- -->
         if (var1 instanceof Bird2) {<!-- -->
            Bird2 var2 = (Bird2)var1;
            if (Double.compare(this.weight, var2.weight) == 0 & amp; & amp; this.age == var2.age & amp; & amp; Intrinsics.areEqual(this.color, var2.color)) {<!-- -->
               return true;
            }
         }

         return false;
      } else {<!-- -->
         return true;
      }
   }
}

/*Is this code very similar to JavaBean code, also has getter/setter,
equals, hashcode, constructor and other methods, where equals and hashcode make
A data class object can be judged like an instance of a common type */

About the componentN() method explanation

& height=598 & amp;id=u054fc60b & amp;name=image.png & amp;originHeight=747 & amp;originWidth=706 & amp;originalType=binary &ratio=1.25 &rotation=0 & showTitle=false &size=149708 &status=done &style=none &taskId=ub2840c47-cde6-439b-82d6-c499b41b5e2 &title= &width=564.8″ alt=” image.png”>
 image.png
 image.png

Pair and Triple

// Look at their source code
//Pair
public data class Pair<out A, out B>(
public val first: A,
public val second: B)
//Triple
public data class Triple<out A, out B, out C>(
public val first: A,
public val second: B,
public val third: C)

// About using
    val pair = Pair(20.0, 1)
    val triple = Triple(20.0, 1, "blue")
//Profit? Attribute order to get the value
    val weightP = pair.first
    val ageP = pair.second
    val weightT = triple.first
    val ageT = triple.second
    val colorT = triple. third
//Of course we can also use? Deconstruction
    val(weightP, ageP) = Pair(20.0, 1)
    val(weightT, ageT, colorT) = Triple(20.0, 1, "blue")

Conventions and uses of data classes?

If you want to declare a data class in Kotlin, the following conditions must be met:
·The data class must have a construction method, which must contain at least two parameters, and a data class without data has no advantages;
·Different from ordinary classes, the parameters of the data class construction method force ?var or val to be declared;
·Abstract, open, sealed or inner cannot be modified before the data class;
·Before version 1.1 of Kotlin, data classes were only allowed to implement interfaces, and later versions can implement interfaces or inherit classes.