Basic concepts of inheritance and composition

  • Inheritance: You can construct a new class based on an existing class. Inheriting existing classes makes it possible to reuse the methods and fields of those classes. From there, new methods and fields can be added to extend the functionality of the class.

  • Composition: Creating an existing object in a new class is called composition. This way you can reuse existing code without changing its form. [Access to information]

1. The inherited syntax extends indicates that a new class is derived from an existing class. An existing class is called a parent or base class, and a new class is called a subclass or derived class. Such as:

class Student extends Person {

}
Copy the code
  • The Student class inherits from Person, which is called a parent or base class, and the Student class is called a subclass or derived class.

2. Synthetic grammar

  • Composition is relatively simple, creating an existing class within a class.
class Student {
   Dog dog;
}
Copy the code

Back modelling

  • 1. Basic concepts
  • The purpose of inheritance is to reuse code. Since inheritance means that all methods of the parent class can also be used in the child class, messages sent to the parent class can also be sent to the derived class. If there is an EAT method in the Person class, then the Student class also has that method, which means that the Student object is also a type of Person. [Obtain information]
class Person {
    public void eat(a) {
        System.out.println("eat");
    }

    static void show(Person p) { p.eat(); }}public class Student extends Person{
    public static void main(String[] args) {
        Student s = new Student();
        Person.show(s);     / / 1.}}Copy the code

【 Result 】 : eat

  • The show method defined in Person receives a Person handle, but receives a reference to the Student object at ①. This is because the Student object is also a Person object. In the show method, the handle passed in (a reference to an object) can be a Person object as well as a derived object of Person. This action of converting a Student handle to a Person handle is called a retrospective cast.

2. Why go up

  • Why is it that when we call eat we intentionally ignore the type of object that called it? It might seem more straightforward to make the show method simply get the Student handle, but that would force each new class derived from the Person class to implement its own show method:
class Value {
    private int count = 1;

    private Value(int count) {
        this.count = count;
    }

    public static final Value
            v1 = new Value(1),
            v2 = new Value(2),
            v3 = new Value(3);
}

class Person {

    public void eat(Value v) {
        System.out.println("Person.eat()"); }}class Teacher extends Person {
    public void eat(Value v) {
        System.out.println("Teacher.eat()"); }}class Student extends Person {
    public void eat(Value v) {
        System.out.println("Student.eat()"); }}public class UpcastingDemo {
    public static void show(Student s) {
        s.eat(Value.v1);
    }

    public static void show(Teacher t) {
        t.eat(Value.v1);
    }

    public static void show(Person p) {
        p.eat(Value.v1);
    }

    public static void main(String[] args) {
        Student s = new Student();
        Teacher t = new Teacher();
        Person p = newPerson(); show(s); show(t); show(p); }}Copy the code

Dynamic binding

  • When we execute show(s), the output is student.eat (), which is exactly what we want, but it doesn’t seem to be executing the way we want.
public static void show(Person p) {
    p.eat(Value.v1);
}
Copy the code
  • It receives a Person handle, so when show(s) is executed, how does it know that the Person handle points to a Student object instead of a Teacher object? The compiler has no way of knowing, which comes down to the binding problem I’ll explain next.

1. Binding of method calls

  • Attaching a method to a method body is called a Binding. If the binding is performed before the run runs, it is called “early binding.” In the example above, with only one Person handle, the compiler doesn’t know which method to call. Java implements a method invocation mechanism that determines the type of an object at run time and then invokes the corresponding method. This type of binding occurs at run time and is based on the type of the object called dynamic binding. Unless a method is declared final, all methods in Java are dynamically bound.
  • Use a diagram to show the inheritance of the up-trace style:

Summarized in code:

Shape s = new Shape();
Copy the code
  • By inheritance, it is legal to assign a created Circle handle to a Shape, since circles are a type of Shape.
  • When one of the underlying class methods is called:
Shape s = new Shape();
Copy the code
  • At this point, circle.draw () is called, due to dynamic binding.
- class Person {
   void eat(a) {}
   void speak(a) {}}class Boy extends Person {
   void eat(a) {
       System.out.println("Boy.eat()");
   }
   void speak(a) {
       System.out.println("Boy.speak()"); }}class Girl extends Person {
   void eat(a) {
       System.out.println("Girl.eat()");
   }
   void speak(a) {
       System.out.println("Girl.speak()"); }}public class Persons {
   public static Person randPerson(a) {
       switch ((int)(Math.random() * 2)) {
       default:
       case 0:
           return new Boy();
       case 1:
           return newGirl(); }}public static void main(String[] args) {
       Person[] p = new Person[4];
       for (int i = 0; i < p.length; i++) {
           p[i] = randPerson();    // Randomly generate Boy or Girl
       }
       for (int i = 0; i < p.length; i++) { p[i].eat(); }}}Copy the code
  • Person establishes a generic interface for all classes derived from Person, and all derived classes have eat and speak behaviors. Derived classes override these definitions, redefining both behaviors. In the main class, randPerson randomly selects the handle to the Person object. The ** appeal occurs in the return statement.
  • The return statement takes a handle to a Boy or Girl and returns it as a Person type, not knowing what type, except that it is a Handle to a Person object. Call the randPerson method in the main method to fill the array with a Person object, but you don’t know what’s going on. When the eat method is called on each element of the array, the dynamic binding performs the object’s redefined method. [Obtain information]
  • However, dynamic binding is a prerequisite; the bound method must exist in the base class or it will not compile.
class Person {
   void eat(a) {
       System.out.println("Person.eat()"); }}class Boy extends Person {
   void eat(a) {
       System.out.println("Boy.eat()");
   }
   void speak(a) {
       System.out.println("Boy.speak()"); }}public class Persons {
   public static void main(String[] args) {
       Person p = new Boy();
       p.eat();
       p.speak();  // The method speak() is undefined for the type Person}}Copy the code
  • If no override method is defined in the subclass, the method in the parent class is called:
class Person {
    void eat(a) {
        System.out.println("Person.eat()"); }}class Boy extends Person {
}
public class Persons {
    public static void main(String[] args) {
        Person p = newBoy(); p.eat(); }}Copy the code

【 result 】: person.eat ()

2. Static method binding

- Add all the above methodsstaticKeyword, become static method:class Person {
    static void eat(a) {
        System.out.println("Person.eat()");
    }
    static void speak(a) {
        System.out.println("Person.speak()"); }}class Boy extends Person {
    static void eat(a) {
        System.out.println("Boy.eat()");
    }
    static void speak(a) {
        System.out.println("Boy.speak()"); }}class Girl extends Person {
    static void eat(a) {
        System.out.println("Girl.eat()");
    }
    static void speak(a) {
        System.out.println("Girl.speak()"); }}public class Persons {
    public static Person randPerson(a) {
        switch ((int)(Math.random() * 2)) {
        default:
        case 0:
            return new Boy();
        case 1:
            return newGirl(); }}public static void main(String[] args) {
        Person[] p = new Person[4];
        for (int i = 0; i < p.length; i++) {
            p[i] = randPerson();    // Randomly generate Boy or Girl
        }
        for (int i = 0; i < p.length; i++) { p[i].eat(); }}}Copy the code

Person.eat() person.eat () person.eat () person.eat () person.eat () person.eat ()

  • Observe that for static methods, no matter what subclass object the superclass reference refers to, the method of the superclass is called. [Obtain information]