How does JVM Understand Java generic classes?

Source: Internet
Author: User

How does JVM Understand Java generic classes?

View plaincopy to clipboardprint?
// Generic code
Public class pair <t>
{
Private t first = NULL;
Private t second = NULL;
Public pair (T fir, t Sec ){
This. First = FIR;
This. Second = sec;
}
Public t getfirst (){
Return this. First;
}
Public t getsecond (){
Return this. Second;
}
Public void setfirst (T fir ){
This. First = FIR;
}
}
// Generic code
Public class pair <t>
{
Private t first = NULL;
Private t second = NULL;
Public pair (T fir, t Sec ){
This. First = FIR;
This. Second = sec;
}
Public t getfirst (){
Return this. First;
}
Public t getsecond (){
Return this. Second;
}
Public void setfirst (T fir ){
This. First = FIR;
}
}

The above is a typical generic code. T is a type variable and can be any reference type.

1. Create an object for generic class
Pair <string> pair1 = new pair ("string", 1);... ①
Pair <string> pair2 = new pair <string> ("string", 1)... ②
There is an interesting phenomenon: ① The Code will not go wrong during compilation, and ② the code will check for errors during compilation.
This problem is actually very simple.
(1) JVM itself does not have a special concept such as generic objects. All generic class objects will be converted into common class objects in the compiler (this will be described in detail below ).
For example, ① and ② the two code compilers all call constructors such as pair (Object fir, object sec.
Therefore, the new pair ("string", 1) in code ① is no problem in the compiler. After all, the compiler does not know which type variable t you create in the pair type, in addition, the compiler affirmed that both the string object and integer object belong to the object type.
However, a classcastexception is thrown when running pair1.getsecond. This is because JVM will calculate that the T-type variable is of the string type based on the first parameter "string", so getsecond should also be of the string type, then the compiler has defaulted that the second operand is an integer type with a value of 1. Of course, it does not meet the JVM running requirements. It is strange not to terminate the program.
(2) but code ② reports an error in the compiler because the new pair <string> ("string", 1) specifies that the type variable t of the pair2 object should be string. Therefore, during compilation, the compiler will know that the error lies in the second integer parameter.
Summary:
When creating a generic object, you must specify the specific type of the type variable t. Try to let the compiler check for errors instead of throwing exceptions when JVM is running.

2. How does JVM understand the generic concept-type erasure?
In fact, JVM does not know about generics. All generics have been processed as common classes and methods in the compilation phase.
The processing method is very simple. It is called erased of type variable t ).
No matter how we define a generic type, an original type is automatically provided. The name of the original type is the name of the generic type of the erased type parameter.
If the type variable of the generic type is not limited (<t>), we use the object as the original type;
If there is a limit (<t extends xclass>), we use xclass as the original type;
If there are multiple limits (<t extends xclass1 & xclass2>), we use the type variable xclass1 class of the first boundary as the original type;
For example, in the above pair <t> example, the compiler regards it as a common class that is replaced by the original object type.

View plaincopy to clipboardprint?
// Compilation stage: erasure of type variables
Public class pair {
Private object first = NULL;
Private object second = NULL;
Public pair (Object fir, object Sec ){
This. First = FIR;
This. Second = sec;
}
Public object getfirst (){
Return this. First;
}
Public void setfirst (Object fir ){
This. First = FIR;
}
}
// Compilation stage: erasure of type variables
Public class pair {
Private object first = NULL;
Private object second = NULL;
Public pair (Object fir, object Sec ){
This. First = FIR;
This. Second = sec;
}
Public object getfirst (){
Return this. First;
}
Public void setfirst (Object fir ){
This. First = FIR;
}
}

3. Generic constraints and limitations-problems caused by type Erasure

(1) It is difficult to inherit the polymorphism of generic types. (-- The subclass does not overwrite the parent class method)

Take a look at the following sonpair class

View plaincopy to clipboardprint?
Class sonpair extends pair <string> {
Public void setfirst (string fir ){....}
}
Class sonpair extends pair <string> {
Public void setfirst (string fir ){....}
}
 

Obviously, the programmer's intention is to overwrite the setfirst (T fir) method of the parent pair <string> In the sonpair class. But in fact, the setfirst (string fir) method in sonpair does not cover this method in pair <string>.
The reason is very simple. Pair <string> has been erased as pair in the compilation phase, and its setfirst method has changed to setfirst (Object FIR ). In sonpair, setfirst (string) cannot overwrite the setfirst (object) of the parent class.

This is indeed a great deal of trouble for polymorphism. Let's look at how the compiler solves this problem.

The compiler automatically generates a bridge method in sonpair ):
Public void setfirst (Object fir ){
Setfirst (string) fir)
}
In this way, the sonpair bridge method can indeed overwrite the setfirst (object) of the generic parent class. In addition, the bridge method actually calls the subclass byte setfirst (string) method. There is no problem with polymorphism.

The problem is not complete yet. Method coverage in polymorphism is acceptable, but the bridge method raises a question:

Now, suppose we want to overwrite the getfirst () method in sonpair?

View plaincopy to clipboardprint?
Class sonpair extends pair <string> {
Public String getfirst (){....}
}
Class sonpair extends pair <string> {
Public String getfirst (){....}
}
 

Because the bridge method is required to overwrite getfirst in the parent class, the compiler automatically generates a public object getfirst () Bridge Method in sonpair.
However, the question is: sonpair shows two methods with the same signature (only the return type is different ):

① String getfirst () // method defined by myself

② Object getfirst () // bridge method generated by the compiler
Does the compiler allow multiple methods with the same method signature to exist in one class?

In fact, there is a knowledge point that everyone may not know:
① The method signature does have only the method name + parameter list. There is no doubt!
② We absolutely cannot compile multiple methods with the same method signature. If you write a program in this way, the compiler will not let go. There is no doubt!
③ The most important thing is that JVM uses the parameter type and return type to determine a method. Once the compiler compiles two methods with the same method signature in some way (only the compiler can create this miracle by itself, but our programmers cannot manually write this code ). The JVM can still identify these methods on the premise that the return types are different.

(2) method conflicts in generic types

Let's look at a piece of code:

View plaincopy to clipboardprint?
// Add the equals Method to the above Code
Public class pair <t> {
Public Boolean equals (T value ){
Return (first. Equals (value ));
}
}
// Add the equals Method to the above Code
Public class pair <t> {
Public Boolean equals (T value ){
Return (first. Equals (value ));
}
}
 

In this case, the code that seems no problem can even pass the compiler:

[Error] Name clash: The method equals (T) of Type pair <t> has the same erasure as equals (object) of type object but does not override it.

The compiler says that your method conflicts with the method in the object. Why?

At first, I didn't quite understand this problem. I felt like the compiler helped us overwrite equals (object) in an object by using methods like equals (t ). After discussion, I think we should explain this question?

First, we all know that the subclass method must be overwritten and must have the same method signature (method name + parameter list) as the parent class method ). In addition, you must ensure the sub-class access permission> = the parent class access permission. This is a fact that everyone knows.

Then, in the above Code, when the compiler sees the equals (t) method in pair <t>, the first response is of course equals (t) the equals (object) in the parent class object is not overwritten.

Then, the compiler replaces (erased) T in generic code with an object ). After the object is erased, equals (t) becomes equals (object). This method is the same as equals in the object class. Based on the idea of starting to determine not to cover such an idea, the compiler is completely crazy (mental splitting ). Then we come to two conclusions: ① stick to the original idea: no coverage. But now, the method conflict is caused. ② Programmers who write this program are crazy (haha ).

Again, the pair <t> object and the T object are compared to equals, just like the ox's head comparison. Haha, It's not logical.

(3) No Generic Array

Pair <string> [] stringpairs = new pair <string> [10];

Pair <integer> [] intpairs = new pair <integer> [10];

The compiler will specify a cannot create a Generic Array of pair <string> error.

After generic erasure, pair <string> [] will become pair [], and can be converted to object [];

If the Generic Array exists

Object [0] = stringpairs [0]; OK

Object [1] = intpairs [0]; OK

This is troublesome. Theoretically, object [] can store all pair objects, but these pair objects are generic objects and their type variables are different, the object methods that call each object [] array element may have different records, maybe a string or an integer, Which is unpredictable to the JVM.

Remember: The element type of an array must be kept in mind, that is, all element objects must be the same. generic types cannot do this. Even if pair <string>, pair <integer>... is of the pair type, they are still different.

Summary: Generic Code and JVM
① There is no generic type in the virtual machine, and there are only common classes and methods.
② In the compilation phase, all type parameters of generic classes are replaced by objects or their limited boundaries. (Type erasure)
③ When inheriting generic types, the bridge method is merged to avoid the polymorphism disaster caused by the erasure of type variables.

 

This article from the csdn blog, reproduced please indicate the source: http://blog.csdn.net/anakinlu/archive/2010/05/10/5574895.aspx

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.