java Generic Parsing (03): Virtual machine Execution Generic code
A Java Virtual machine does not have a generic type object, all objects belong to the normal class, even in the early version of the generic implementation, A program that uses generics can be compiled into a class file that can run on a 1.0 virtual machine, and this backward compatibility is discarded later, so if generic code compiled with the Sun's compiler is not running on a virtual machine prior to Java5.0, this leads to some actual production problems, such as how some legacy code is related to the new System to understand the problem, you need to understand how the virtual machine executes generic code. a mechanism for a virtual machine:
erasing a type parameter and replacing it with a specific type, without specifying a specific type with object instead , as in the previous Couple<t> class, after the virtual machine is erased:
[CODE01]
public class Couple { private Object wife; Private Object husband; Public Couple (Object wife, object husband) { this.wife = wife; This.husband = husband; } public void Setwife (Object wife) {this. wife = wife;} public void Sethusband (Object husband) {this. husband = husband;} Public Object Getwife () {return wife;} Public Object Gethusband () {return husband;} }
The type parameter T is an arbitrary type, so the erase is replaced with object. Either couple<employee> or couple<string> erase has become the original class couple class, which is like returning to the generic class before generics introduce Java. So here's the focus around the
erase type parameter mechanism. What if there is a type qualification for the type parameter? The erase type parameter mechanism tells us that using a qualified type instead, if there is more than one, use the first instead to see a piece of code:
[CODE02]
public class Period<t extends Comparable<t> & serializable> { private T begin; Private T end; Public Period (t one, T,) { if (One.compareto (both) > 0) {begin = Two;end = one; } else {begin = One;end = ;} } }
after the CODE02 is erased, the original type of period is as follows:
[CODE03]
public class Period { private comparable begin; private comparable end; Public Period (comparable one, comparable) { if (One.compareto (both) > 0) {begin = both; end = one; } else { begin = One; end = Both;}}}
Think about it if period<t
extends comparable<t> & Serializable> written as period<t
extends serializable & COMPARABLE<T> > what's going to happen? In the same vein, After erasing the original type with the first serializable instead, so that when the CompareTo method calls, the compiler will do the necessary coercion type conversion, so in order to improve efficiency, the label interface (no method interface, also known as tagging interface) is placed behind. Let's look at what happens when a virtual machine executes an expression, such as: [CODE04]
Couple<employee> Couple = ...; Employee wife = Couple.getwife ();
after erasing, Getwife () returns an object type, and then the virtual machine inserts a forced type conversion and converts the object to employee, so the VM actually executes a two-day instruction:1. Call the Couple.getwife () method. 2. Convert object to employee type. Let's look at what happens when a virtual machine executes a generic method, such as:
[Code05]
public static <t extends comparable<t>> max (t[] arrays) {...} Erased: Public staticcomoparable max (comparable[] arrays) {...}
However, the erasure of a generic method brings two complex problems, and looks at the first instance, one instance:
[CODE06]
public class Period <t extends Comparable<t> & serializable> { Private T begin; Private T end; Public Period (t one, T,) {if (One.compareto (both) > 0) {begin = Two;end = one; } else {begin = One;end = both;} public void SetBegin (T-Begin) {this. begin = Begin;} public void SetEnd (T-end) {this. end = end;} Public T Getbegin () {return begin;} Public T Getend () {return end;} } public class DateInterval extends period<date> {public DateInterval (date one, date) { Super (one, both); public void SetBegin (Date begin) {super.setbegin (begin); } }
after the dateinterval type is erased, the method in period becomes: public void
setbegin (Object begin) { ... }
and the method in DateInterval is:public void
setbegin ( Date begin) {...} So DateInterval inherited from the period.
Public
void SetBegin (Object begin) {... } and the existence of itself
Public
void SetBegin (Date begin) {...} method, the problem occurs when the user is using:
[Code07]
period<date> Period = new DateInterval (...); Period.setbegin (New Date ());
here, because the period reference points to the DateInterval instance, SetBegin should invoke the SetBegin method of the DateInterval object, depending on polymorphism, but this erase lets
the public in period
void setbegin (Object begin) {... } was called, causing the erase to conflict with polymorphism, what to do? The virtual machine now generates a bridge method in the DateInterval class, with a slight change in the invocation process:
[Code08]
public void SetBegin (Object begin) { setbegin (Date) begin);
with this synthetic bridge method, the following steps are called for SetBegin in code07:
1. Call the Dateinterval.setbegin (Object) method. The 2.dateinterval.setbegin (Object) method invokes the Dateinterval.setbegin (Date) method. Did you find out what it would look like when we added the Getbegin method to the DateInterval? Is there an object Getbegin () method in Peroid, and there is a date Getbegin () method in DateInterval, and these two methods cannot exist in Java at the same time? But Java5 later added a covariant type, so that this is allowed, see DateInterval in the Getbegin method to know: [Code09]
@Override public Date Getbegin () {return super.getbegin ();}
here @override is used, which means that the object Getbegin () method is overridden for the parent class, and the return value can be specified as a subclass of the return value type in the parent class, which is the covariant type, which is allowed after Java5. Allows subclasses to override a method and specify a more restrictive type (subtype).
Summary:1. Remember that there are no generics in the virtual machine, only ordinary classes. 2. All generic type parameters are replaced with their qualified type, and object is not qualified. 3. In order to maintain type safety, the virtual machine inserts a forced type conversion if necessary. 4. The synthesis of the bridge method is used to preserve polymorphism. 5. Covariant types allow subclasses to override a method and return a more restrictive type.
Java Generic Parsing (01): Understanding Generics
Java Generic Parsing (02): Wildcard Qualifier
Java Generic Parsing (03): Virtual Machine Execution Generic code
Java Generic Parsing (03): Virtual machine execution Generic code