Polymorphism is generally divided into two types: rewrite polymorphic and overloaded polymorphic. Overriding and overloading these two points of knowledge before the article has detailed the results, here is not much to say.
Overloaded polymorphic, also called compile-time polymorphism. In other words, this polymorphic recompilation is already determined. Overloading everyone knows that a set of methods with the same method name and a different argument list is overloaded. When this overloaded method is called, different results are obtained by passing in different parameters.
But there are ambiguities, and some people feel that overloading should not be counted as polymorphic. Because many people's understanding of polymorphism is that the specific type of reference variable defined in the program and the method call made through that reference variable are not deterministic during programming, but are determined during the program's run, which is known as polymorphism. This definition describes our second polymorphic-rewrite polymorphism. Also, overloaded polymorphism is not unique to object-oriented programming, but polymorphism is one of the three main features of object-oriented (if I'm wrong, remember to tell me.) )。
I don't think it's necessary for us to go into these definitions, and my understanding is that the ability to have many different forms or forms of the same behavior is polymorphic, so I think overloading is also a polymorphic, and if you disagree with that view, I accept it.
Rewrite polymorphic, also called run-time polymorphism. This polymorphism is implemented by dynamic binding, which refers to the actual type of the referenced object during execution and invokes its corresponding method according to its actual type. That is, only if the program is running, do you know which subclass of the method is called.
This polymorphism is achieved through the rewriting of functions and the upward transformation, and the example in our code above is a complete rewrite polymorphism. All of the polymorphic states we're going to talk about are rewrite-polymorphic, because it's really polymorphic in object-oriented programming.
Upward transformation
The object that the subclass refers to is converted to a parent class type called upward transformation. In layman's words, a subclass object is converted to a parent class object. The parent class object can be an interface here.
Let's look at an example that everyone knows:
PublicClassAnimal {PublicvoidEat () {System.out.println ("Animal eatting ...");}PublicClassCatExtendsanimal{PublicvoidEat () {System.out.println ("I eat fish"); }}PublicClassDogExtendsanimal{public void eat () { System.out.println ( "I eat Bones");} public void run () { System.out.println ( "I'll Run");}} public class main {public static void main (string[] args) {Animal Animal = new Cat () ; //upward Transformation animal.eat (); animal = new Dog (); Animal.eat ();}} //results: //I eat fish //I eat Bones
This is the upward transformation, Animal Animal = new Cat (), and the subclass object Cat into the parent class object Animal. This time animal the method called by the reference is a subclass method.
Issues needing attention in the process of transformation
- When you move up, the methods that are defined by subclasses are lost. For example, the Run method defined in the above dog class, when the animal reference to the dog class instance is not accessible to the Run method,
animal.run()
will error.
- The subclass reference cannot point to the parent class object.
Cat c = (Cat)new Animal()
This is not going to work.
Benefits of upward transformation
- Reduce duplication of code and make your code concise.
- Improve system scalability.
Down transformation
and the upward transformation of the corresponding is the downward transformation. The downward transformation transforms the parent object into a subclass object. (Please note!) There's a hole in here. )
Case-driven
Let's look at an example:
//还是上面的animal和cat dogAnimal a = new Cat();Cat c = ((Cat) a);c.eat();//输出 我吃鱼Dog d = ((Dog) a);d.eat();// 报错 : java.lang.ClassCastException:com.chengfan.animal.Cat cannot be cast to com.chengfan.animal.DogAnimal a1 = new Animal();Cat c1 = ((Cat) a1);c1.eat();// 报错 : java.lang.ClassCastException:com.chengfan.animal.Animal cannot be cast to com.chengfan.animal.Cat
Why does the first piece of code not error? As you know, because A is a cat object in itself, so it's a matter of course to turn down to cat, and for granted it can't be turned into dog, you've seen a dog suddenly become a cat this motherfucker phenomenon?
A1 is a animal object, and it cannot be transformed downward to any subclass object. For example, you go to archaeology, you find a new creature, you know it's an animal, but you can't just say, ah, it's a cat, or it's a dog.
Down transition considerations
See a classic case:
Class A {Public StringShow (D obj) {Return ("A and D"); }Public StringShow (A obj) {Return ("A and a"); }}class B extends a{Public StringShow (B obj) {Return ("B and B"); }Public StringShow (A obj) {Return ("B and A"); }}class C extends B{}class D extends b{}PublicClassDemo {PublicStaticvoidMain (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 ("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));}} //results: //1--a and A//2--A and A< Span class= "Hljs-comment" >//3--a and D//4--b and A//5--B and A< Span class= "Hljs-comment" >//6--a and D//7--b and B//8--B and B< Span class= "Hljs-comment" >//9--a and D//can you read the result? Let's start with a self-analysis.
The first three, forced analysis, but also can read. But the fourth one, maybe you're stupid. Why not B and B?
We're going to learn something new here.
When a parent class object references a variable that references a subclass object, the type of the referenced object determines which member method to call, and the reference variable type determines the callable method. If the method is not overridden in a subclass, it is looked for in the parent class.
It might be a bit of a mouthful to read, so let's start with a simple example:
ClassY ZPublicvoid show (Y y) {System.out.println ("X and Y"); }Publicvoid Show () {System.out.println ("Only X"); }}class y extends X {public void Show (Y y) {System.out.println (public void Show (int i) {}}class main{ Public static void Main (string[] args) {x x = new Y (); X.show (new Y ()); X.show ();}} //results //y and Y//only x
Y inherits X, overwrites the show (Y Y) method in X, but does not overwrite the show () method.
At this point, the reference to X for x refers to the object Y, and at this point the method called is determined by Y, which is looked up first from Y. Execution x.show(new Y());
, the method is defined in Y, so the method in Y is executed;
But x.show();
when it's done, some people will say, Y doesn't have this method? It seems to be looking for the method in the parent class because the method in X is called.
In fact, there is a show () method in the Y class, this method inherits from X, but does not overwrite the method, so it is not explicitly written in Y, it looks like the method called in X, actually called in Y.
It's not hard to understand the hard-to-understand words at this time. X is a reference variable type, which determines which methods can be called, Show () and show (Y y) can be called, and show (int i) cannot be called. Y is the type of the referenced object that determines whose method to call: The method that calls Y.
The above is a simple knowledge, it is not enough to let us understand the complex example. Let us look at such a knowledge:
The priority of the invocation of an object method in the inheritance chain: This.show (O), Super.show (O), This.show (Super) O, Super.show ((Super) O).
If you can understand this invocation relationship, then polymorphism you have mastered. Let's go back to that complex example:
The ABCD relationship is like this:c/d-> b-> A
Let's first analyze 4:a2.show(b)
- First, A2 is a reference type of type A, which points to an object of type B. A determines the callable methods: Show (D obj) and show (A obj).
a2.show(b)
==> this.show(b)
, here This refers to B.
- And then. Find Show (b obj) in class B, but it's useless because the show (b obj) method is not in the callable range,
this.show(O)
fails, and goes to the next level: super.show(O)
, super refers to a.
- Find Show (B obj) in a, failed because this method is not defined. Enter the third level:
this.show((super)O)
, this refers to B.
- In B, look for Show ((a) O), find: Show (a obj), choose to call the method.
- Output: B and A
If you can understand the process, and can analyze other situations, then you really have mastered it.
Let's take another look at 9:b.show(d)
- First, B is a reference object of type B, pointing to an object of type B. Does not involve an upward transformation, only the methods in this class are called.
- In B, look for show (D obj), method. Now you're not going to say you haven't found it, are you? Found, call the method directly.
- Output A and D.
Summarize
This is basically what this article is about. Let's sum it up.
- Polymorphism, in short, is the ability of the same behavior to have many different manifestations or forms.
- Polymorphic classification: Run-time polymorphism and compile-time polymorphism.
- Prerequisites for Runtime Polymorphism: Inheritance (Implementation), rewriting, upward transformation
- Transform up and down.
- The priority of the invocation of an object method in the inheritance chain: This.show (O), Super.show (O), This.show (Super) O, Super.show ((Super) O).
Polymorphism in Java