Painted inheritance

open class Base(p: Int)
class Derived(p: Int) : Base(p)
Copy the code

(1) To inherit, the subclass needs to inherit the parent class, the subclass is responsible for the parent class field initialization

class Derived(p: Int) : Base(p)

(2) All subclasses end up calling the primary constructor of the parent class for initialization. The primary constructor of a subclass always calls the primary constructor of the parent class by default. Therefore, if a subclass has no primary constructor, the secondary constructor can call the primary/secondary constructor of the parent class with super

open class Base(val p: Int) {
    // Name can be initialized in a block of init code instead of "". It will eventually be merged into the main constructor
    var name: String = ""
    constructor(p: Int, name: String): this(p) {
        this.name = name
    }
}

class Derived : Base {
    // If the subclass does not explicitly write out the primary constructor, the secondary constructor needs to use super to actively call the parent constructor (primary or secondary).
    constructor(p: Int) : super(p) {}
    constructor(p: Int, name: String) : super(p, name) {}
}
Copy the code

If the class needs to be inherited, this should be explicitly written out as the Open class name, otherwise the default is public Final

Override method (override method)

To inherit the parent class marked with open

The function is to be overridden, and the superclass function is marked open

A subclass overrides a superclass function, using the override flag function

Subclasses do not allow the open function to be overridden again, adding final to mark the function

open class Shape {
    open fun draw(a){}}open class Circle : Shape() {
    // If class Circle is final open Circle, the function is also final and can be written without display
    final override fun draw(a){}}Copy the code

Covering properties

A subclass has the same attribute name as its parent

open class Shape {
    open val vertexCount: Int = 0
}

class Rectangle : Shape() {
    override var vertexCount: Int = 1
}
Copy the code

On fields: (Field visibility is always private)

(1) If val is used, the field is private final by default, and the get/set method only generates public GET

Var is private and generates get/set functions

var ==> private ==> final get/set

All the functions generated above are final (get/set are all final)

If you add open to a field, it will affect the get/set function. If you add open to a field, the final of get/set will disappear

(2) You can also override a val attribute with a var attribute, but not vice versa. This is allowed because a val attribute essentially declares a get method, while overwriting it as var simply declares an additional set method in a subclass

The subclass wants the vertexCount field to have only the GET method and be final, but the parent class already has a set method. By default, the subclass inherits the parent class’s public Final set method

The initialization order of subclasses ▲

Explore how to create subclass objects in the initialization order

open class Base(val name: String) {
   init {
      println(2. Superclass init code block)}open val size: Int = this.name.length.also { println("3. The parent constructor performs size object initialization")}}class Derived(name: String, val lastName: String) :
   Base(name.capitalize().also { println("1. The initialization code block of the Derived constructor performs initialization.") {})init {
      println("4.Derived init code block execution")}override val size: Int =
      (super.size + lastName.length).also { println("5. Initialize the size field Derived")}}fun main(args: Array<String>) {
   val derived = Derived("zhazha"."xixi")}Copy the code

The specific order is:

1The initializer block of the.Derived constructor performs the initialization2. Superclass init code block3The superclass constructor performs size object initialization4The.Derived init code block is executed5Initialize the size field DerivedCopy the code

Call the parent class stuff ★

open class Rectangle {
    open fun draw(a) { println("Drawing a rectangle")}val borderColor: String get() = "black"
}
class FillRectangle : Rectangle() {
    override fun draw(a) {
       // super calls the superclass function
        super.draw()
        println("Filling the rectangle")}// Call the properties of the parent class, where the getBorderColor() function is called
    val fillColor: String get() = this.borderColor
}
Copy the code

(1) Super is generally used to call attributes or methods of the parent class

open class Rectangle {
   open fun draw(a) {
      println("Drawing a rectangle")}val borderColor: String get() = "black"
}

class FilledRectangle : Rectangle() {
   override fun draw(a) {
      // super calls the superclass function
      super.draw()
      println("Filling the rectangle")}// Call the properties of the parent class, where the getBorderColor() function is called
   val fillColor: String get() = this.borderColor
   
   inner class Filler {
      fun fill(a) {
         println("Filling ")}fun draw(a) {
         println("Filler draw...")}fun drawFill(a) {
         // idea intelligent prompt is not very good for this, it needs to be written by the user, no prompt
         // Only the inner class can access the outer class's methods, and the parent of the FilledRectangle class is called draw
         super@FilledRectangle.draw()
         fill()
         println("fillColor = $fillColor")
         // Call Filler's draw
         draw()
         // Call FilledRectangle's draw
         this@FilledRectangle.draw()
         println("class rectangle color: ${[email protected]}")}}}fun main(args: Array<String>) {
   val rectangle = FilledRectangle()
   rectangle.draw()
   rectangle.Filler().drawFill()
}
Copy the code

1) super @ AAA class. BB method (), which calls the BB method ② this@AAA class of the parent class of AAA. BB method (), which calls the BB method of class AAA

Covers the rules

open class Rectangle {
   open fun draw(a) {
      println("rectangle draw...")}}interface Polygon {
   fun draw(a)
}

class Square() : Rectangle(), Polygon {
   // Although both parent classes have draw methods, one of them is an interface, and the other already has a function body, so it calls the implemented method directly
}

fun main(args: Array<String>) {
   val square = Square()
   square.draw()
}
Copy the code

If there are two classes, you need to override the desired method directly

interface Rectangle {
    fun draw(a) {
        println("Rectangle draw...")}}interface Polygon {
    fun draw(a) {
        println("Polygon draw...")}}class Square : Rectangle.Polygon {
    // Class 'Square' must override public open fun draw(): Unit defined in relation04.cover02.Rectangle because it inherits multiple interface methods of it
    override fun draw(a) = println("Square draw...")}fun main(args: Array<String>) {
    val square = Square()
    square.draw()
}
Copy the code

The default functions of both interfaces have the same name, and subclasses need to manually override this method to define their own draw function

interface Rectangle {
   fun draw(a) = println("Rectangle draw...")}interface Polygon {
   fun draw(a) = println("Polygon draw...")}class Square : Rectangle.Polygon {
   override fun draw(a) {
      super<Rectangle>.draw()
      super<Polygon>.draw()
      println("Square draw...")}}fun main(args: Array<String>) {
   val square = Square()
   square.draw()
}
Copy the code

An abstract class to end

abstract class Polygon {
    abstract fun draw(a)
}

class Rectangle : Polygon() {
    override fun draw(a) {
        println("Rectangle draw...")}}Copy the code

You can also override non-abstract Open member functions with abstract member functions

open class Polygon {
    open fun draw(a) {
        println("Polygon draw...")}}abstract class Rectangle : Polygon() {
    // The subclass overwrites the parent's open method as abstract
    abstract override fun draw(a)
}
Copy the code

Visibility modifier

Classes, objects, interfaces, constructors, methods, properties, and their setters can all have visibility modifiers (getters always have the same visibility as properties)

There are four visibility modifiers in Kotlin: private, protected, internal, and public. If no specified visibility modifier is displayed, the default is public

package

  • If no visibility modifier is specified, the default top-level declaration is public
  • If declared private, it can only be used within the file
  • If declared internal, it will be used anywhere in the module (as in Java’s default)
  • This modifier is not supported in the protected package

Classes and interfaces

  • Private: indicates that the class is visible internally. All members, including its internal members, can be used only within the class
  • Protected: Indicates that members of the class are visible under subclasses of the entire family of classes
  • Internal: visible throughout the module
  • Public: visible anywhere

As with Java, external classes cannot access private inner classes

If a protected member is overridden and no visibility modifier is specified, the default remains protected

open class Outer {
    private val a = 1
    protected open val b = 2
    internal val c = 3
    val d = 4  / / public by default
    
    protected class Nested {
        public val e: Int = 5}}class Subclass : Outer() {
    // A is not visible
    // b, C, d
    // Nested and e are visible
    override val b = 5   / / "b" is protected
}

class Unrelated(o: Outer) {
    // O.a, O.B are not visible
    // o.c and O.D visible (same module)
    // Nested. Nested:: E was also invisible
}
Copy the code

The constructor

To specify the visibility of a class’s main constructor, use the following syntax (note that you need to add an explicit constructor keyword) :

Class C private constructor(a: Int) {... }

The constructor here is private. By default, all constructors are public, which essentially equals that the class is visible wherever it is visible

A local variable

Local variables, functions, and classes do not support visibility modifiers

The module

The internal visibility modifier means that the member is visible only within the same module, and a module is a bunch of Kotlin files compiled together, for example:

  • An IDEA module
  • A Maven project
  • A Gradle source-set (except that the test source-set has access to the internal declaration of main)
  • At a time<kotlinc>The Ant task executes a compiled set of files
internal class Button : View {
    private fun yell(a) = println("Hey!")

    protected fun whisper(a) = println("Let's go!")}fun Button.giveSpeech(a) { // Error trying to convert public class to internal class
    println(this: :class.java)
}
Copy the code

Data class to end

Data classes are similar to how Java adds the Lombok annotation @data to bean-related classes

data class User(val name: String, val age: Int)
Copy the code
public final class User {
   @NotNull
   private final String name;
   private final int age;

   @NotNull
   public final String getName(a) {
      return this.name;
   }

   public final int getAge(a) {
      return this.age;
   }

   public User(@NotNull String name, int age) {
      Intrinsics.checkNotNullParameter(name, "name");
      super(a);this.name = name;
      this.age = age;
   }

   @NotNull
   public final String component1(a) {
      return this.name;
   }

   public final int component2(a) {
      return this.age;
   }

   @NotNull
   public final User copy(@NotNull String name, int age) {
      Intrinsics.checkNotNullParameter(name, "name");
      return new User(name, age);
   }

   // $FF: synthetic method
   public static User copy$default(User var0, String var1, int var2, int var3, Object var4) {
      if ((var3 & 1) != 0) {
         var1 = var0.name;
      }

      if ((var3 & 2) != 0) {
         var2 = var0.age;
      }

      return var0.copy(var1, var2);
   }

   @NotNull
   public String toString(a) {
      return "User(name=" + this.name + ", age=" + this.age + ")";
   }

   public int hashCode(a) {
      String var10000 = this.name;
      return(var10000 ! =null ? var10000.hashCode() : 0) * 31 + Integer.hashCode(this.age);
   }

   public boolean equals(@Nullable Object var1) {
      if (this! = var1) {if (var1 instanceof User) {
            User var2 = (User)var1;
            if (Intrinsics.areEqual(this.name, var2.name) && this.age == var2.age) {
               return true; }}return false;
      } else {
         return true; }}}Copy the code

The compiler automatically exports the following members from all properties declared in the main constructor:

  • equals() / hashCode();
  • toString()Format is “User(name=John, age=42)”;
  • componentN()Functions correspond to all attributes in declarative order;
  • copy()Function.

To ensure consistent and meaningful behavior in generated code, data classes must meet the following requirements:

  • The main constructor needs to take at least one argument;
  • All arguments to the main constructor need to be marked with val or var;
  • Data classes cannot be abstract, open, sealed, or internal;
  • (Prior to 1.1) data classes could only implement interfaces.

In addition, member generation follows these rules about member inheritance:

  • If there is an explicit implementation in the data class bodyequals()hashCode()ortoString()Or these functions may exist in the parent classfinalImplementation, then these functions will not be generated, but existing functions will be used;
  • If the supertype hasopencomponentN()Function and return a compatible type, the corresponding function is generated for the data class and overrides the implementation of the superclass. If these functions of the supertype are incompatible due to signatures or arefinalAnd cause cannot overwrite, then will report an error;
  • From one already hasCopy (...)Function and the type whose signature matches a derived data class was deprecated in Kotlin 1.2 and disabled in Kotlin 1.3.
  • Do not allow forcomponentN()As well ascopy()Function provides explicit implementation.

If the code is written like this:

data class User(val name: String = "".val age: Int = 0)
Copy the code

It will provide a no-argument constructor

The Data class uses only fields in the main constructor as templates for generating code, such as copy Equals, and properties that are not in the active constructor are not used as elements of the generated code

data class Person(val name: String) {
    val age: Int = 0
}
Copy the code

This way age is not used to generate code

copy

data class User(val name: String = "", val age: Int = 0)

fun main(args: Array<String>) {
   val user: User = User("zhazha", 1)
   val user1 = user.copy(name = "xixi")
   println(user)
   println(user1)
}
Copy the code

After some attributes are filled in, other attributes retain their previous values

Data classes and deconstruction declarations

The Component functions generated for the data classes make them usable in destructible declarations:

val j = User("zhazha".22)
val (name, age) = j
println("name = $name, age = $age")
Copy the code

Sealed class being

A sealed class is the counterpart of an enumerated class, which tries to list all finite subclasses (multiple types), while an enumerated class tries to list all objects (multiple objects).

To declare a sealed class, use the keyword sealed modifier. The subclasses of the sealed class must all be in the same file as the sealed class

sealed class Expr

data class Const(val number: Double) : Expr() {
}
data class Sum(val e1: Expr, val e2: Expr) : Expr()

object NotANumber : Expr()

fun main(args: Array<String>) {
   // Application scenario
   fun eval(expr: Expr): Double = when(expr) {
      is Const -> expr.number
      is Sum -> eval(expr.e1) + eval(expr.e2)
      NotANumber -> Double.NaN
   }
}
Copy the code

Inner and nested classes ★

The default is nested classes

A Kotlin class can have classes inside it, and there are two kinds of relationships between inner and inner classes: nested classes (the default) and inner classes (the inner modifier is required)

Kotlin’s nested classes show up static when decompiled into Java, which is nice in this case

interface State : Serializable

interface View {
    fun getCurrentState(a): State
    fun restoreState(state: State)
}
Copy the code

If this is Java code, the implementation is as follows:

public class Button02 implements View { @Override public State getCurrentState() { return new ButtonState(20, "name"); } @Override public void restoreState(State state) { } class ButtonState implements State { private Integer age; private String name; public ButtonState(Integer age, String name) { this.age = age; this.name = name; } } public static void main(String[] args) throws Exception { Button02 button02 = new Button02(); System.out.println(button02.getCurrentState()); ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("D://test.txt")); NotSerializableException OutputStream.writeObject (button02.getCurrentState())); outputStream.flush(); outputStream.close(); }}Copy the code

A single ButtonState can be serialized, but the ButtonState is the inner class, which secretly hides the this object of the outer class. This object does not support serialization, so an error is reported

If you change ButtonState to static, you won’t get an error

static class ButtonState implements State

Kotlin doesn’t have this problem

The class kotlin writes inside the class, which is nested by default and static, does not store this inside the outer class

private class Button01 : View {
    lateinit var buttonState: State

    override fun getCurrentState(a): State = ButtonState(12."haha")

    override fun restoreState(state: State) {
        this.buttonState = state
    }

    private class ButtonState(_age: Int, _name: String) : State {
        val age: Int = _age
        val name: String = _name
    }
}

fun main(a) {
    val button01 = Button01()
    with(ObjectOutputStream(File("""D:\test.txt""").outputStream())) {
        writeObject(button01.getCurrentState())
        flush()
        close()
    }
// ObjectOutputStream(File("""D:\test.txt""").outputStream()).apply {
// writeObject(button01.getCurrentState())
// flush()
// close()
/ /}
}
Copy the code

Kotlin uses the inner modifier to define inner classes

inner class ButtonState02 {}Copy the code