Implementation of Java Generics: Principles and issues

Source: Internet
Author: User
Tags type casting

It's been a long time since I wrote a blog because of the project and some personal reasons. Recently review to find work, reading + recall the project after some experience, and blog stop more so long since the accumulation, is something to write. From now on, slowly the accumulation of things to fill up, to facilitate the leakage after the leak.

Let's start with the latest. Yesterday to see the Java generic related content, some doubts, check the information found that this part is very interesting things, such as the type of erasure caused by the rewrite problem, and recorded in this article.

1. Generic definition

Read a lot of generic explanation Baidu Encyclopedia, explain 1, explain 2, is not what I want "to use as the" answer (not understand the role of generics or design purposes), here I summarize:
Generic programming is a technique that decouples data processing from the type of a dataset by parameterization, by imposing constraints on the data type (such as a bounded type in Java) to ensure the correctness of the processing, also known as parameter types or parameter polymorphism.
The most famous application of generics is the container, the STL of C + +, the collection Framework of Java.

2. How generics are implemented

Different languages implement generics in different ways, C + + templates will be compiled at compile time according to different types of parameters generated different code, and Java generics is a type of violation, compiled into bytecode when the parameter type is erased in the code, separately recorded in the class file in the attributes domain, Instead, type checking and type casting are done using generics.
Assuming the placeholder for the parameter type is T, the erase rule is as follows:

    • <T> changed to OBECJT after erasing
    • <? Extends a> to A after erasing
    • <? Super A> becomes object after erasing

The above erase rule is called 保留上界 .

3. Problems with erasing

For <? Extends a> and <? Super A> Erase, because 保留上界 , so erase does not destroy after 里氏替换原则 .
There are classes Super and sub:

class Super{}class Sub extends Super{}

For 有界类型 covariance and inverse degeneration:

List<?listnew ArrayList<Sub>();  //协变List<?new ArrayList<Super>();   //逆变

After the type is erased, it is equivalent to:

Listlistnew ArrayList<Sub>();Listnew

As you can see, the erasure of the parameter type does not undermine the Richter substitution principle, which is 保留上界 why.

Thanks to the author of the blog in Java, I have a good understanding of covariance and contravariance and pecs rules. I will write a summary of my own when I have the chance.

For the erasure of <T>, depending on where the T appears in the class, the following 5 scenarios are discussed:

    1. T is the type of the member variable
    2. T is a type parameter of a generic variable, whether a member variable or a local variable, commonly known as class<t>,list<t>.
    3. T is the Exception that the method throws (requires <t extends exception>)
    4. T is the return value of the method
    5. T is the parameter of the method

The erase of Scenario 1 has no effect, because the compiler adds type conversions where generics are called;
There is no problem with the erase of situation 2, which is a bit like "to implement immutable classes, it is necessary to ensure that the reference point of the member variable is also immutable", is a recursive definition;
The erasure of the situation 3, I think the discussion of this situation is of little significance. Want to throw T in the method, that must first instantiate T, and how to instantiate through generics, forgive me I do not know how to do it (some people say that reflection can do, blame my reflection study bad ...) Suppose you now get and can throw an instance of a generic t and see what happens.
There are classes Super and sub:

class  super  <t  extends   sqlexception  >{ public  void  Test () throws t{} // Don't doubt, this code can be compiled by ... } class  sub  extends   super  << Span class= "Hljs-title" >batchupdateexception  >{ @Override public  void  Test () throws batchupdateexception{} // This must be consistent with the parameter type, or the compilation will not pass. }

After the super parameter type is erased, it becomes:

class Super<SQLException>{    publicvoidtestthrows SQLException{}}

When compared to the sub class, it is found that there are no rules that violate the method override (override) in Java.

Java override rules have a good memory of the formula, called "Two with two small One big" (actually called "two with two narrow one wide" I feel better), said is the sub-class method and the parent class method similarities and differences:
-the method name & parameter list of the subclass method is the same as the parent class method.
-The return type of the subclass method is a subclass of the parent method return type (covariant return type, narrower scope);
-The subclass method throws fewer exceptions than the parent method throws (narrower scope);
-The access control permissions of the subclass method are greater than the parent class method (the access scope is wider).
This rule can be conveniently used to reverse the introduction of the Richter replacement principle. It is clear that this type of erasure does not violate the rules for exceptions when overridden.

The case 4 is called T as the return type is erased, because the covariant return type exists, it also does not have a problem.
There are two classes of super and sub:

class Super<T>{    T test(){}}class Sub extends Super<String>{    @Override    protected String test(){}  //这里抖个包袱:protected拥有比package更高的访问权限,可以被同一包内的类访问}

After type erase, Super becomes:

class Super{    Object test(){}}

Compared with the Sub class, you can see that it does not violate the "two and two small one big" formula, so there will be no problem.

This is called covariant return type, that is, the return value of the subclass method is the subclass of the parent method (tongue twisters ...). )。 The JVM uses the bridge method (Acc_bridge) when implementing it, which is described later.

The situation 1,2,3,4 has been analyzed and found that, under the existing language specification, type Erasure does not have an impact, and case 5 is somewhat different.
With class Super and sub

class Super<T>{    publicvoid test(T arg){}}class Sub extends Super<String>{    @Override    publicvoidstr){}}

And then look at the Super parameter type after being erased:

class  super  { public  void  Test (Object Arg) {}}class  sub  extends   super  {   @Override public  void  test (String str ) {}}  

This time I even write the sub together, is to facilitate the comparison: the above code compiles without passing, because the subclass of the overridden method parameter list and the parent class is inconsistent! Subclasses are String and the parent class is Object .
However, we write according to the type before the erase, the compiler does not have an error, the execution result also proves that we really rewrite the method, then the Java (accurate compiler) How to do it? Take a look at the following picture, which is the byte code of the sub class:

Notice that the Sub class has two test methods, one of the parameter types is String , this is the method overridden in the sub, the other parameter type is Object , and flags has more than ACC_BRIDGE ACC_SYNTHETIC two labels. View 深入理解Java虚拟机 6.3.6节 表6-12 , ACC_BRIDGE which indicates that this is a compiler-generated bridge method, which ACC_SYNTHETIC means that this method is generated automatically by the compiler. Watch out for what this method does:

#19#21

The Chang of sub is shown in the following table:

As you can see, the bridge method first determines Object String whether the type conversion is correct. invokevirtualis an instruction that invokes an object method and is dispatched according to the actual type of the object. As you can see from the constant pool, the bridge method invokes the overridden method in the sub class. This ensures that type erasure under Scenario 5 does not break the semantics of method overrides.

4. Bridge method for covariant return type

协变返回类型It is also implemented using the bridge method, which is the byte code:

Interestingly: There are two signatures in a class file, just a different method of returning values. If this is the case in the Java source code, the compilation will not pass. Why is it possible to compile a class file?
Think about it, the reason why this overload method is not allowed in the Java source code is to avoid ambiguity in the method invocation, such as:

publictest(){    return"obj";}publictest(){    return"str";}publicstaticvoidmain(String[] args){    System.out.println(new Super().test());}

At this point the compiler is unable to determine which one test() to call, so it is simply forbidden. At runtime, the JVM has enough methods to differentiate this ambiguity (for example, with ACC_BRIDGE ACC_SYNTHETIC these two flags), so it can be allowed to exist.

5. Summary

There are two questions throughout: How Java generics are implemented (simply speaking), and what the problem is with this implementation (focus on speaking). This involves the,,, (the name of the 里氏替换原则 协变与逆变 most low 协变返回类型 两同两小一大口诀 ... ), 桥方法 these concepts.
This blog post is intended to explain the principles and to help the practical application too much. There will be a succession of blog post, such as Arrays.sort source code, such as generics how to achieve covariance and inversion.

Implementation of Java Generics: Principles and issues

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.