Understand the three major features of java polymorphism

Object-oriented programming has three characteristics: encapsulation, inheritance, and polymorphism.

      Encapsulation hides the internal implementation mechanism of the class, and the internal structure of the class can be changed without affecting the use, while also protecting the data. Its internal details are hidden from the outside world, and only its access methods are exposed to the outside world.

      Inheritance is to reuse parent class code. Two classes can use inheritance if there is an IS-A relationship. , while inheritance also paved the way for polymorphism. So what is polymorphism? What is the implementation mechanism of polymorphism? Please watch me unveil them for you one by one:

      The so-called polymorphism means that the specific type pointed to by the reference variable defined in the program and the method call issued through the reference variable are not determined during programming, but are determined during the running of the program, that is, which reference variable will point to. The instance object of the class, the method in which the method call issued by the reference variable is the method implemented in the class must be determined during the running of the program. Because the specific class is determined when the program is running, the reference variable can be bound to various class implementations without modifying the source code, so that the specific method called by the reference changes accordingly, that is, no modification is made. The program code can change the specific code bound when the program runs, so that the program can choose multiple running states, which is polymorphism.

      For example, you are a Dionysian and have a soft spot for alcohol. When I came home one day, I found that there were several glasses on the table filled with white wine. From the outside, it was impossible for us to know what kind of wine it was. Only after drinking it could we guess what kind of wine it was. Once you drink it, it is Jiannanchun, drink it again, it is Wuliangye, and drink it again, it is Jiuguijiu... Here we can describe it as follows:

      Wine a = Jiannanchun

      Wine b = Wuliangye

      wine c = alcoholic wine

      …

      What's here is polymorphism. Jiannanchun, Wuliangye, Jiuguijiu are all subclasses of wine. We can refer to different subclasses only through the parent class of wine. This is polymorphism - we only know when the reference variable is running. instance object.

      Of course, to understand polymorphism we must understand what "upcasting" is. In the inheritance, we briefly introduced the upward transformation, and here is the long-winded: in the drinking example above, wine (Win) is the parent class, and Jiannanchun (JNC), Wuliangye (WLY), and Jiuguijiu (JGJ) are subclasses. We define the following code:

      JNC a = new JNC();

      It is very easy for us to understand that this code is nothing more than instantiating an object of Jiannanchun! But so what?

      Wine a = new JNC();

      Here we understand this, here defines a Wine type a, which points to the JNC object instance. Since JNC inherits from Wine, JNC can be automatically converted to Wine, so a can point to the JNC instance object. This has a very big advantage. In inheritance, we know that the subclass is an extension of the parent class, which can provide more powerful functions than the parent class. If we define a parent class reference type that points to the subclass, then it is in addition to In addition to being able to refer to the commonality of the parent class, you can also use the powerful functions of the subclass.

      But there are some drawbacks of upcasting, that is, it will inevitably lead to the loss of some methods and properties, so that we can't get them. Therefore, the reference of the parent class type can call all the properties and methods defined in the parent class, and it is beyond the reach of methods and properties that only exist in the subclass---1.

copy code
public class Wine {
    public void fun1(){
        System.out.println("Wine 的Fun.....");
        fun2();
    }
    
    public void fun2(){
        System.out.println("Wine 的Fun2...");
    }
}

public class JNC extends Wine{
    /**
     * @desc subclass override superclass method
     * This method does not exist in the parent class. After upcasting, the parent class cannot reference this method
     * @param a
     * @return void
     */
    public void fun1(String a){
        System.out.println("JNC 的 Fun1...");
        fun2();
    }
    
    /**
     * Subclass override superclass method
     * When the parent class reference pointing to the subclass calls fun2, this method must be called
     */
    public void fun2(){
        System.out.println("JNC 的Fun2...");
    }
}

public class Test {
    public static void main(String[] args) {
        Wine a = new JNC();
        a.fun1();
    }
}
-------------------------------------------------
Output:
Wine 的Fun.....
JNC's Fun2...
copy code

      From the running results of the program, we found that a.fun1() firstly runs fun1() in the parent class Wine. Then it runs fun2() in the subclass JNC.

      Analysis: In this program, the subclass JNC overloads the method fun1() of the parent class Wine, rewrites fun2(), and the overloaded fun1(String a) and fun1() are not the same method, because in the parent class Without this method, the method will be lost after upcasting, so the Wine type reference that executes JNC cannot reference the fun1(String a) method. The subclass JNC overrides fun2(), so the Wine reference pointing to JNC will call the fun2() method in JNC.

      So for polymorphism we can summarize as follows:

      The parent class reference pointing to the subclass can only access the methods and properties owned by the parent class due to upcasting, and for methods that exist in the subclass but do not exist in the parent class, the reference cannot be used, although it is heavy. load this method. If the subclass overrides some methods in the parent class, when calling these methods, the methods defined in the subclass must be used (dynamic connection, dynamic call).

      For object-oriented only, polymorphism is divided into compile-time polymorphism and run-time polymorphism. Among them, polymorphism is static during editing, which mainly refers to the overloading of methods. It distinguishes different functions according to the different parameter lists. After editing, it will become two different functions, which is not polymorphic at runtime. . And runtime polymorphism is dynamic, it is achieved through dynamic binding, which is what we call polymorphism.

Implementation of polymorphism

      2.1 Implementation conditions

      It was mentioned at the beginning that inheritance is preparing for the realization of polymorphism. The child class Child inherits the parent class Father, we can write a parent class type reference pointing to the child class, which can handle both the parent class Father object and the child class Child object. When the same message is sent to the child class or the parent class object, the object will perform different behaviors according to the reference to which it belongs, which is polymorphism. That is, polymorphism is that the same message makes different classes respond differently.

      There are three necessary conditions for Java to implement polymorphism: inheritance, rewriting, and upcasting.

         Inheritance: In polymorphism there must be subclasses and superclasses that have an inheritance relationship.

         Overriding: The subclass redefines some methods in the parent class, and when these methods are called, the methods of the subclass are called.

         Upcasting: In polymorphism, the reference of the subclass needs to be assigned to the object of the superclass, only in this way can the reference have the skills to call the methods of the superclass and the methods of the subclass.

         Only when the above three conditions are met, can we use unified logic implementation code in the same inheritance structure to process different objects, so as to achieve different behaviors.

      For Java, its implementation mechanism of polymorphism follows a principle: when a superclass object references a variable that references a subclass object, the type of the referenced object rather than the type of the reference variable determines whose member method is called, but this called The method must be defined in the superclass, that is, the method overridden by the subclass.

      2.2 Realization form

      There are two forms of polymorphism in Java. Inheritance and Interfaces.

      2.2.1. Polymorphism based on inheritance

      The implementation mechanism based on inheritance is mainly manifested in the overriding of certain methods by the parent class and one or more subclasses that inherit the parent class, and the overriding of the same method by multiple subclasses can show different behaviors.

copy code
public class Wine {
    private String name;
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Wine(){
    }
    
    public String drink(){
        return "Drink is" + getName();
    }
    
    /**
     * Override toString()
     */
    public String toString(){
        return null;
    }
}

public class JNC extends Wine{
    public JNC(){
        setName("JNC");
    }
    
    /**
     * Override the parent class method to achieve polymorphism
     */
    public String drink(){
        return "Drink is" + getName();
    }
    
    /**
     * Override toString()
     */
    public String toString(){
        return "Wine : " + getName();
    }
}

public class JGJ extends Wine{
    public JGJ(){
        setName("JGJ");
    }
    
    /**
     * Override the parent class method to achieve polymorphism
     */
    public String drink(){
        return "Drink is" + getName();
    }
    
    /**
     * Override toString()
     */
    public String toString(){
        return "Wine : " + getName();
    }
}

public class Test {
    public static void main(String[] args) {
        //Define the parent class array
        Wine[] wines = new Wine[2];
        //define two subclasses
        JNC jnc = new JNC();
        JGJ jgj = new JGJ();
        
        //The parent class refers to the child class object
        wines[0] = jnc;
        wines[1] = jgj;
        
        for(int i = 0 ; i < 2 ; i++){
            System.out.println(wines[i].toString() + "--" + wines[i].drink());
        }
        System.out.println("-------------------------------");

    }
}
OUTPUT:
Wine : JNC--drinking JNC
Wine : JGJ--drinking JGJ
-------------------------------
copy code

      In the above code, JNC and JGJ inherit Wine and rewrite the drink() and toString() methods. The result of the program running is to call the method in the subclass and output the names of JNC and JGJ. This is the performance of polymorphism. Different objects can perform the same behavior, but they all need to do it through their own implementation, thanks to upcasting.

      We all know that all classes inherit from the superclass Object, and the toString() method is also a method in Object, when we write:

Object o = new JGJ();

      System.out.println(o.toString());

 

      The output is Wine : JGJ.

      The inheritance chain relationship of Object, Wine, and JGJ is: JGJ—>Wine—>Object. So we can say this: when a subclass overrides the superclass's method is called, only the method at the end of the object inheritance chain will be called. But be careful if you write:

 

Object o = new Wine();

System.out.println(o.toString());

  The output should be Null, because JGJ does not exist in the object inheritance chain.

      Therefore, polymorphism based on inheritance can be summarized as follows: For the parent class type that refers to a subclass, when processing the reference, it applies to all subclasses that inherit the parent class. The implementation of the method is different depending on the subclass object. Different, the behavior of performing the same action will be different.

      If the parent class is an abstract class, then the child class must implement all the abstract methods in the parent class, so that all the child classes of the parent class must have a unified external interface, but their internal specific implementations can be different. This way we can use the uniform interface provided by the top-level class to handle the methods at that level.

      2.2.2. Polymorphism based on interface implementation

      Inheritance is manifested by several different subclasses that override the same method of the parent class, then it can be manifested by several different classes that implement the interface and override the same method in the interface.

      In interface polymorphism, a reference to an interface must be an instance program that specifies a class that implements the interface. At runtime, the corresponding method is executed according to the actual type of the object reference.

      Inheritance is single inheritance, which can only provide a consistent service interface for a group of related classes. But the interface can be multi-inheritance and multi-implementation, it can use a group of related or unrelated interfaces to combine and expand, and can provide a consistent service interface to the outside world. So it has better flexibility than inheritance.

Third, the classic example.

      Through the above description, it can be said to have a certain understanding of polymorphism. Now strike while the iron is hot and see an example. This example is a classic example of polymorphism, taken from: http://blog.csdn.net/thinkGhoster/archive/2008/04/19/2307001.aspx .

copy code
public class A {
    public String show(D obj) {
        return ("A and D");
    }

    public String show(A obj) {
        return ("A and A");
    }

}

public class B extends A{
    public String show(B obj){
        return ("B and B");
    }
    
    public String show(A obj){
        return ("B and A");
    }
}

public class C extends B{

}

public class D extends B{

}

public class Test {
    public static void main(String[] args) {
        A a1 = new A();
        A a2 = new B();
        B b = new B();
        C c = new C();
        D d = new D();
        
        System.out.println("1--" + a1.show(b));
        System.out.println("2--" + a1.show(c));
        System.out.println("3--" + a1.show(d));
        System.out.println("4--" + a2.show(b));
        System.out.println("5--" + a2.show(c));
        System.out.println("6--" + a2.show(d));
        System.out.println("7--" + b.show(b));
        System.out.println("8--" + b.show(c));
        System.out.println("9--" + b.show(d));      
    }
}
copy code

      operation result:

copy code
1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D
copy code

      Looking at the results 1, 2, and 3 here, it's easy to understand, but I've been confused since 4. Why is the output not "B and B" for 4?

      First let's look at a sentence: when a superclass object reference variable references a subclass object, the type of the referenced object rather than the type of the reference variable determines whose member method is called, but the called method must be in the superclass Defined, that is, methods that are overridden by subclasses. This sentence summarizes polymorphism. In fact, there is a priority in the invocation of object methods in the inheritance chain: this.show(O), super.show(O), this.show((super)O), super.show((super)O).

      First of all, we analyze 5, a2.show(c), a2 is a reference variable of type A, so this represents A, a2.show(c), it is found in class A and not found, so it goes to the superclass of A Find (super), because A has no superclass (except Object), so jump to the third level, that is, this.show((super)O), the superclass of C has B and A, so (super)O is B, A, this is also A, where show(A obj) is found in A, and since a2 is a reference of class B and class B rewrites show(A obj), the subclass class B will eventually be called The show(A obj) method, the result is B and A.

      Following the same approach I can confirm other answers as well.

      The method has been found, but we still have a little doubt here, let's look at this sentence: when a superclass object references a variable that references a subclass object, the type of the referenced object, not the type of the reference variable, determines whose member method is called , but the called method must be defined in the superclass, that is, the method overridden by the subclass. Here we use an example to illustrate the meaning of this sentence: a2.show(b);

      Here a2 is a reference variable, of type A, which refers to the B object, so according to the above sentence, it means that there is B to decide whose method to call, so a2.show(b) should call the show in B (B obj), the result should be "B and B", but why is it different from the previous run result? Here we ignore the latter sentence "but the method called here must be defined in the superclass", so does show(B obj) exist in class A? It doesn't exist at all! So this sentence doesn't apply here? So is this sentence wrong? Not too! In fact, this sentence also implies this sentence: it still has to be confirmed according to the priority of calling methods in the inheritance chain. Therefore, it will find show(A obj) in class A, and at the same time, because B has rewritten the method, it will call the method in class B, otherwise it will call the method in class A.

      Therefore, the principles followed by the polymorphism mechanism are summarized as follows: when a superclass object references a variable to a subclass object, the type of the referenced object rather than the type of the reference variable determines whose member method is called, but the called method must be in the The method defined in the superclass, that is to say, the method overridden by the subclass, but it still needs to confirm the method according to the priority of the method call in the inheritance chain, the priority is: this.show(O), super.show(O ), this.show((super)O), super.show((super)O).

      Reference: http://blog.csdn.net/thinkGhoster/archive/2008/04/19/2307001.aspx .

      Baidu Wenku: http://wenku.baidu.com/view/73f66f92daef5ef7ba0d3c03.html

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324817862&siteId=291194637