Type conversions for Java polymorphic objects
The object type conversion referred to here refers to an object that has an inheritance relationship and is not an object of any type. When an object that does not have an inheritance relationship is coerced for type conversion, the Java runtime throws a Java.lang.ClassCastException exception.
In the inheritance chain, we call subclasses to the parent class "transition upward", and the parent class to the subclass is called "downward transition."
Often, we define variables as the type of the parent class, but refer to the subclass's object, which is a process of upward transformation. When the program runs, it implements the invocation of the subclass method through dynamic binding, that is, polymorphism.
However, sometimes in order to complete some of the functions that the parent does not have, we need to turn the transformed subclass object into subclasses and invoke the subclass method, which is the downward transformation.
Note: You cannot cast an object of a parent class directly into a subclass type, you can only convert a subclass object that has been transformed to a subclass type. In other words, the subclass object must be transformed upwards before it can be transformed downward. Take a look at the following code:
public class Demo {public
static void Main (String args[]) {
Superclass superobj = new superclass ();
Sonclass sonobj = new Sonclass ();
The following code throws an exception when it is run, and the parent class object cannot be directly converted to a subclass type
//Sonclass sonObj2 = (sonclass) superobj;
First upward transformation, then downward transformation
superobj = sonobj;
Sonclass sonObj1 = (sonclass) superobj;
}
}
Class superclass{}
class Sonclass extends superclass{}
The comment in line 7th is removed, and the runtime throws an exception, but the compilation can pass.
Because there is a risk of a downward transition, be sure to use the instanceof operator when you receive a reference to the parent class to determine whether the object is the subclass you want, and see the following code:
public class Demo {public
static void Main (String args[]) {
Superclass superobj = new superclass ();
Sonclass sonobj = new Sonclass ();
Superobj is not an instance of the Sonclass class
if (superobj instanceof sonclass) {
Sonclass sonObj1 = (sonclass) superobj;
} else{
System.out.println ("① cannot convert");
}
Superobj = sonobj;
Superobj is an instance of the Sonclass class
if (superobj instanceof sonclass) {
Sonclass sonObj2 = (sonclass) superobj;
} else{
System.out.println ("② cannot convert");
}} Class superclass{}
class Sonclass extends superclass{}
Run Result:
Summary: The type conversion of an object is checked at run time, the upward transition occurs automatically, and the object being transformed must be a subclass of the current reference type.
Java polymorphism and dynamic binding
In Java, a variable of a parent class can refer to an instance of a parent class, or to an instance of a subclass.
Let the reader read a piece of code first:
public class Demo {public
static void Main (string[] args) {
Animal obj = new Animal ();
Obj.cry ();
obj = new Cat ();
Obj.cry ();
obj = new Dog ();
Obj.cry ();
}
Class animal{
//animal calls public
void Cry () {
System.out.println ("Don't know how to call");
}
Class Cat extends animal{
//cat calls public
void Cry () {
System.out.println ("Meow ~");
}
Class Dog extends animal{
//dog calls public
void Cry () {
System.out.println ("barking ~");
}
Run Result:
Don't know how to call
Meow Meow ~
Bark ~
The above code, which defines three classes, is Animal, Cat, and Dog,cat and Dog classes are inherited from the Animal class. The obj variable is of type Animal, it can point to an instance of the Animal class, or it can point to an instance of the Cat and the Dog class, which is correct. That is, a variable of the parent class can refer to an instance of the parent class, or to an instance of a subclass. Note that the converse is wrong, because all cats are animals, but not all animals are cats.
It can be seen that obj can be either human or cat or dog, it has different manifestations, which is called polymorphism. Polymorphism means that a thing has a different form or form of expression.
Another example is "human", there are a lot of different expression or realization, TA can be drivers, teachers, doctors, etc., you hate yourself will say "Next life", then you become a driver, teachers, doctors can, we say "human" with polymorphism.
There are three necessary conditions for polymorphic existence: inheritance, overriding, and parent-class variables referencing child-class objects.
When a method is invoked using polymorphic methods:
First check whether the method is in the parent class, if not, compile the error, and if so, check whether the subclass overrides the method.
If the subclass overrides the method, the method of the subclass is invoked, otherwise the parent class method is invoked.
One of the benefits of polymorphism, as you can see from the above example, is that when subclasses are relatively long, there is no need to define multiple variables, and you can define only a variable of a parent class type to refer to instances of different subclasses. Please look at one of the following examples:
public class Demo {public
static void Main (string[] args) {
//with polymorphism, hosts can feed many animals
Master ma = new Master ();
Ma.feed (New Animal (), New Food ());
Ma.feed (New Cat (), New Fish ());
Ma.feed (New Dog (), New bone ());
}
Animal class and its subclasses class
animal{public
void Eat (Food f) {
System.out.println ("I am a small animal, eating" + f.getfood ());
}
}
Class Cat extends animal{public
void Eat (Food f) {
System.out.println ("I'm a kitten, eating" + f.getfood ());
}
}
Class Dog extends animal{public
void Eat (Food f) {
System.out.println ("I'm a dog, eating" + f.getfood ());
}
}
//Food and its subclass class
food{public
String Getfood () {return
"things";
}
}
Class Fish extends food{public
String Getfood () {return
"fish";
}
}
Class Bone extends food{public
String Getfood () {return
"bone";
}
}
Master Class class
master{public
void Feed (Animal, Food f) {
an.eat (f);
}
}
Run Result:
I am a small animal, eating things
I am a kitten, eating fish
I am a dog, eating bones
The feed method of the master class has two parameters, namely the Animal type and the Food type, because it is a parent class, so you can pass an instance of the subclass to it so that the master class does not require multiple methods to feed different animals.
Dynamic Binding
To understand the nature of polymorphism, here's a detailed flow of Java invocation methods.
1 The compiler looks at the declared type and method name of the object.
Suppose call Obj.func (param), obj is an object of the Cat class. It should be noted that there may be more than one method whose name is func but the parameter signature is different. For example, methods func (int) and func (String) may exist. The compiler will enumerate all the methods named Func in all Cat classes and the methods named Func in their parent class Animal that have access properties public.
The compiler then obtains a list of all the candidate methods that might be invoked.
2) Next, the codec checks the parameter signature provided when the method is invoked.
Select this method if there is a method that exactly matches the supplied parameter signature in all methods named Func. This process is referred to as overload resolution (overloading resolution). For example, if you call func ("Hello"), the compiler chooses Func (String) instead of func (int). Because of the existence of an automatic type conversion, such as int can be converted to double, if no method is found that is the same as calling the method parameter signature, the type conversion is done and then the lookup continues, if there is no matching type or if multiple methods match, compile error.
The compiler then obtains the method name and parameter signature that needs to be invoked.
3 If the modifier of the method is private, static, final (static and final will be explained later), or is a construction method, then the compiler will be able to know exactly which method should be called, which we call the static binding binding).
In this case, the invoked method relies on the actual type of the object and implements dynamic binding at run time. For example, call func ("Hello"), and the codec will dynamically bind to generate an instruction that calls Func (String).
4 when the program is run and the method is invoked with dynamic bindings, the JVM must invoke the method of the class that is most appropriate to the actual type of object referenced by obj. We have assumed that the actual type of obj is Cat, it is a subclass of Animal, and if Func (String) is defined in cat, it is called, otherwise it will be found in the Animal class and its parent class.
Each invocation of the method is searched for a considerable amount of time, so the JVM creates a method table for each of the classes (methods lable) that lists the names of all methods, the signature of the parameters, and the class to which they belong. This way, when the method is actually invoked, the virtual machine only looks for the table. In the example above, the JVM searches the method table of the Cat class to find a way to match the call to func ("Hello"). This method can be either Cat.func (string) or Animal.func (string). Note that if you call Super.func ("Hello"), the compiler will burst the search on the parent class's method table.
Assuming that the Animal class contains Cry (), GetName (), Getage () Three methods, its method table is as follows:
Cry ()-> animal.cry ()
GetName ()-> animal.getname ()
Getage ()-> animal.getage ()
In fact, Animal also has the default parent class Object (which is explained later) that inherits the method of object, so the methods listed above are not complete.
Assuming that the Cat class overwrites The Cry () method in the Animal class and adds a new method Climbtree (), its argument list is:
Cry ()-> cat.cry ()
GetName ()-> animal.getname ()
Getage ()-> animal.getage ()
Climbtree ()-> cat.climbtree ()
At run time, the procedure for invoking the Obj.cry () method is as follows:
The JVM first accesses the method table of the actual type of obj, possibly the method table for the Animal class, or the method table for the Cat class and its subclasses.
The JVM searches the method table for a method that matches the cry () and finds out what class it belongs to.
The JVM invokes the method.