Separating things that change from things that don’t change — polymorphism
Polymorphism refers to procedures defined in the reference variable is pointing to the specific type and referenced by the variable from method calls are not sure when programming, but during the program is run to determine, that is, a reference variable STLL can point to which class instance object, the reference variable from method calls the method to realize exactly is which class, It must be decided during the running of the program. Because the program is running to identify a specific class, so, don’t need to modify the source code, can make reference variables bound to the different class implements, leading to the reference call specific methods change, namely do not modify the program code can change the program of the specific binding in the runtime code, let the program can select multiple running state, this is polymorphism
Example: Instrument include Wind
///:~
class Instrument{
public void paly(){
System.out.println("Instrument.play()");
}
public void fix(){
System.out.println("Instrument.play()");
}
}
///:~
class Wind extends Instrument{
@Override
public void paly() {
System.out.println("Wind.play()");
}
public void fix(String s) {
System.out.println("Wind.fix()");
}
}
///:~
public class Main {
public static void main(String[] args) {
//...
Wind wind = new Wind();
tune(wind);
}
public static void tune(Instrument i){
i.paly();
i.fix();
}
}
/*Output:
Wind.play()
Instrument.play()
*///:~Copy the code
Upcasting: A reference to an object (Wind) as a reference to its base type (Instrument) is called ~
In main.tune (), we point an Instrument I to the Wind object instance. Since Wind is an inherited Instrument, the interface of the so-called Instrument must exist in Wind, so Wind can be automatically transformed upward into Instrument. Moving from Wind to Instrument may “shrink” the interface, but it is no narrower than the entire interface of Instrument. References to superclass types can call all properties and methods defined in the superclass, and it is far beyond the reach of methods and properties that only exist in subclasses.
A parent reference to a subclass can only access methods and properties owned by the parent class because it has been upcast, and a reference to a method that exists in a subclass but does not exist in the parent class cannot be used, albeit by overloading the method. If a subclass overrides a method in its parent class, it must use the methods defined in the subclass to call those methods (dynamic linking, dynamic calling). Since paly() is overridden and fix() is overloaded, there is no fix(String) method in the parent class. Therefore, an Instrument reference to Wind cannot refer to the fix(String) method. If subclass Wind overrides play(), an Instrument reference to Wind calls the Play () method in Wind.
For object orientation, polymorphism is divided into compile-time polymorphism and run-time polymorphism. Among them, when editing polymorphism is static, mainly refers to the method overload, it is according to the different parameter list to distinguish different functions, after editing will become two different functions, not polymorphic at run time. While runtime polymorphism is dynamic, it is achieved through dynamic binding, which we call polymorphism.
Implementation of polymorphism
conditions
The implementation of Java polymorphism requires three things: inheritance, rewriting, and upward transition
The realization mechanism of polymorphism follows the following principles:
When a superclass object references a variable that references a subclass object, the type of the referenced object, not the type of the referenced variable, determines whose member method is called, but the method being called must be defined in the superclass, that is, the method overridden by the subclass.
The realization form
Implementation of polymorphism in the form of inheritance and interface (both)
Inheritance-based implementation
The implementation mechanism based on inheritance is mainly manifested in the rewriting of some methods by the parent class and one or more subclasses that inherit the parent class. Multiple subclasses can show different behaviors when rewriting the same method.
class Instrument{
public void paly(){
System.out.println("Instrument.play()");
}
public void fix(){
System.out.println("Instrument.play()");
}
}
///:~
class Wind extends Instrument{
@Override
public void paly() {
System.out.println("Wind.play()");
}
public void fix() {
System.out.println("Wind.fix()");
}
}
///:~
class Stringed extends Instrument{
@Override
public void paly() {
System.out.println("Stringed.play()");
}
@Override
public void fix() {
System.out.println("Stringed.play()");
}
}
///:~
public class Main {
public static void main(String[] args) {
//...
Instrument[] i = {new Stringed(),new Wind()};
for (Instrument instrument:i) {
instrument.paly();
instrument.fix();
}
}
}
/*Output:
Stringed.play()
Stringed.play()
Wind.play()
Wind.fix()
*///:~Copy the code
The Wind,Stringed code inherits Instrument and overrides the play(),fix() methods. The result of the program is to call the methods in the subclass. This is the performance of polymorphism. This is due to the upward transition.
For example, the superclass Object if we have a paly() method in our superclass when we write it this way
///:~
///:~
///:~
Object o = new Wind()
System.out.println(o.play());
/*Output:
Wind.play()
*///:~Copy the code
///:~
///:~
///:~
Object o = new Instrument()
System.out.println(o.play());
/*Output:
Instrument.play()
*///:~Copy the code
When a subclass overrides a parent class, only the last method in the object’s inheritance chain is called.
So inheritance based polymorphisms can be summarized as follows: for a type of a parent class that refers to a subclass, when dealing with that reference, it applies to all subclasses that inherit from that parent class. Different subclass objects will implement different methods and perform different behaviors when performing the same action.
If the parent class is abstract, then the subclass must implement all the abstract methods in the parent class, so that all the subclasses of the parent class must have the same external interface, but their internal concrete implementation can be different. This allows us to use the uniform interface provided by the top-level class to handle methods at that level.
Interface based implementation
Inheritance is represented by overriding several different subclasses of the same method in the parent class, and thus by implementing the interface and overriding several different classes of 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 and, at run time, executes the corresponding method according to the actual type of the object reference.
Inheritance is single inheritance and can only provide a consistent service interface for a set of related classes. But the interface can be multiple inheritance and multiple implementation, it can use a group of related or unrelated interface combination and expansion, can provide a consistent external service interface. So it has more flexibility than inheritance.
Reference instance
class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
class C extends B{
}
class D extends B{
}
public class Main {
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));
}
}
/*Output:
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 the code
When a superclass refers to a variable that refers to a subclass, the type of the referenced object, not the type of the referenced variable, determines whose member method is called, but the method being called must be defined in the superclass, that is, the method overridden by the subclass. That’s a generalization of polymorphism. Show (O), super.show(O), this.show((super)O), super.show((super)O).
5, a2. Show (c), a2 is A reference variable of type A, so this represents A, a2. Show (c), A superclass (super), A superclass (except Object), A superclass (super) This. Show ((super)O), C has A superclass B and A, so (super)O is B and A, this is also A, a2 is A reference to B, and B overwrites show(A obj). So the show(A obj) method of subclass B is eventually called, resulting in B and A.
For example, 4, a2. Show (b), a2 is A reference variable, type A, this is a2, b is an instance of B, so it looks for the show(b obj) method in class A. So this. Show ((super)O), this is still a2, where O is B, (super)O is (super)B is A, so it goes to class A to find the method show(A obj), class A has this method, but since A2 refers to an object of class B, B overrides A’s show(A obj) method, so it eventually locks to show(A obj) of class B, with the output “B and A”.
For example, 8, b. how(c), b is A reference variable, type b, this is b, c is an instance of C, so it looks for the show(c obj) method in class B, but it doesn’t find it in superclass A. This. Show ((super)O), this = b, O = C, (super)O = (super)C = b, so it looks for the show(b obj) method in b, and finds it, because b references an object of class B, So lock directly to show(B obj) of class B and output “B and B”.
Methods have found there is a doubt but we here, let’s look at this sentence: when the superclass object reference variable reference subclass object, is the type of the reference object rather than a reference variable type whose members decided the call method, but this is the method called must be defined in a superclass, method that is covered by a subclass. Here’s an example of what this means: a2. Show (b)
Show (B) should call show(B obj) from B. The result should be “B and B”. But the method called here must be defined in the superclass. Show (B obj) exists in class A. It doesn’t exist! So that doesn’t apply here? So is this sentence wrong? Not too! It is still validated by the priority of the method called in the inheritance chain. That’s why it finds show(A obj) in class A, and because B overrides the method it calls the method in class B, otherwise it would call the method in class A
Conclusion:
When the superclass object reference variable subclass object reference and cited the type of object rather than a reference variable type determines the call who is a member of the method, but this is the method called must be defined in a superclass, that is covered by a subclass method, but it still according to the priority of a method call in the inheritance chain to confirm the method, the priority is: this.show(O)->super.show(O)->this.show((super)O)->super.show((super)O)
extension
Method call binding
Associating a method call with a method body is called binding, binding before the program executes is called early binding, and late binding is used in polymorphism. All methods in Java except static and final methods are late binding
Pitfalls: Domain and static methods
class Super{
public int field = 0;
public int getField(){
return field;
}
}
class Sub extends Super{
public int field =1;
public int getField() {
return field;
}
public int getSuperField() {
return super.field;
}
}
public class Main {
public static void main(String[] args) {
//...
Super sup = new Sub();
System.out.println(sup.field+" "+sup.getField());
Sub sub = new Sub();
System.out.println(sub.field+" "+sub.getField()+" "+sub.getSuperField());
}
}
/*Output:
0 1
1 1 0
*///:~Copy the code
When a Sub object is transformed into a Super reference, any domain operations will be resolved by the compiler and therefore not polymorphic
class Instrument{
public static void paly(){
System.out.println("Instrument.play()");
}
public void fix(){
System.out.println("Instrument.play()");
}
}
///:~
class Wind extends Instrument{
public static void paly() {
System.out.println("Wind.play()");
}
public void fix() {
System.out.println("Wind.fix()");
}
}
///:~
public class Main {
public static void main(String[] args) {
//...
Instrument instrument = new Wind();
instrument.fix();
instrument.paly();
}
}
/*Output:
Wind.fix()
Instrument.play()
*///:~Copy the code
If a method is static, its behavior is not polymorphic. Static methods are associated with classes, not individual objects