Why is Java using type erase to implement generics?

Source: Internet
Author: User
Tags xquery

Why generics are required?

Imagine that you need a simple container class, or a handle class, for example to store an apple basket, and you can do so simply:

fruit{}fruit{}apple apple; public void set (this.apple;}}  

Such a simple basket would be implemented, but the problem is that it only stores apples, and then there is another pile of fruit, and you have to implement containers for these fruit classes separately:

Classfruit{}ClassAppleExtendsfruit{}ClassBananaExtendsfruit{}ClassOrangeExtendsfruit{}Classbucketapple{PrivateApple Apple; public void Set (Apple Apple) {This.apple = Apple; } publicApple get () {ReturnThis.apple; }}class bucketbanana{private banana Banana; public void set (banana Banana) { this.banana = Banana;} Public banana get () {return  This.banana; }}class bucketorange{private orange Orange;java Learning Group 669823128 public void Set ( orange Orange) {this.orange = orange;} public orange get () {return this.orange;}}         

Then you find that you are actually doing a lot of repetitive work. So you fantasize about your language. If the compiler supports a feature, it will help you generate the code automatically.

But before you ask the compiler to help you generate the code, it suddenly occurred to you that object could refer to anything of any kind, so you could just write a bucket of type object to hold any type.

bucket{    object;    This . This . object;}}   

But the problem is that the type of the container is missing, and you have to add the type conversion where the output is:

New bucket (); bucket. Set (new Apple ()); Apple (apple) bucket. get ();  

And you can't guarantee that the container is Apple, because object can point to any reference type.

At this point you may want to ask the compiler to help you with these types of checks.

Say here, you should understand the generics to guarantee two things, first: I just need to define the class once, can be used by "any" type, instead of defining a class for each type. Second: My generics can only hold the types I specify, not a bunch of object references.

In fact, the generics of many languages are based on the above two points, and I will explain how the c++,java,c# generics are implemented separately. The reason for this comparison is to explain why it is so implemented, and what the pros and cons are.

C + + macros

Most people have studied C in college, and you must remember that there is something called a macro in C that macros can "replace" the code during the pre-compilation period. Because C + + is compatible with C, macros are also available in C + +.

For example, the following code:

#Define square (x) x*xint a = Square (5);  

After the preprocessing period, all of your code is square(5); replaced 5*5 .

Similarly, a template in C + + is called a high-level macro, when we define a bucket template class in C + +. You can declare different types of template implementations separately.

#Include<iostream>template<Class t>Class bucket{Private:t stuff;PublicvoidSet(T T) {This->stuff = t; }TGet(){Returnthis->stuff; }};class fruit{}; class Apple: public fruit{}; Class Banana: public fruit{}; Class Orange: public fruit{}; int main () { std::cout <<  "Hello, world! "<< std::ENDL; Bucket<apple> Applebucket; Applebucket. set (Apple ()); Bucket<banana> bananabucket; Bananabucket. set (Banana ()); return 0;}         

And when you compile, the C + + template will be expanded to look something like this:

Bucket_apple  {    private:       Apple  stuff;    Public :        this->stuff;} };

So you can see why the C + + template is generic, because it helps you generate different types of code.

In fact, the C + + template is also known as: compile-time polymorphic technology, the function is far more powerful than generics. We often hear: "C + + meta-programming", the so-called technique of generating code with code. is based on its template.

But one drawback of this technique is that if I were to declare 100 different types of fruit containers, it would probably generate 100 copies of the code. The large number of C + + code that uses the template, the compiled file will be very large. (guessing that some compilers might do optimizations, which I'm not very clear about, welcome.) )

Java

Java generics Use the object reference on the underlying implementation, which is the second way we mentioned earlier, but to prevent you from adding a banana to an apple bucket. The compiler will first perform a static type check based on the generic type you declared, then type-erase, and erase to object. The so-called type checking is at the boundary (where the object enters and leaves), checking to see if the type conforms to a certain constraint, and simply includes:

    1. The left and right side types of an assignment statement must be compatible.
    2. The actual participation of a function call must be compatible with its formal parameter type.
    3. The expression type of return must be compatible with the return value type defined by the function.
    4. There are also polymorphic type checks, which can be passed directly through the upward transformation, but a downward transition must enforce the type conversion (provided there is an inheritance relationship)
Integer (1);  Integer b = (integer) n;  

It is important to note, however, that the compiler will only check if the inheritance relationship is compliant. If there is a problem with the strong turn itself, it will be discovered at run time. So the following line of code throws an exception at run time.

N is IntegerDouble d = (Double) n; 

So you cannot insert a string object in a ArrayList, but the type of the generic class that is printed is the same:

arraylist<New arraylist<integer> (); arraylist<New arraylist<new ArrayList (); System.out.println (Arraylistint.getclass (). GetName ()); System.out.println (Arrayliststring.getclass (). GetName ()); System.out.println (Arraylist.getclass (). GetName ()); # All Print java.util.ArrayList    

However, this technique also has a disadvantage, that is, since it is wiped into an object, then at run time, you are not sure what the object is exactly what type, although you can use the compiler to help you insert the checkcast to get the type of this object. But you can't actually use T as a type: This statement is illegal in Java, for example.

New T ();

Similarly, because all are wiped into object, you cannot make a distinction based on type. For example, exception inheritance:

Errorcatch (someexception<string> e) {}

such as overloading:

Errorvoid f (list<t> v);  void f (list<w> v);   

Also, because the primitive type int is not part of OOP, it cannot be erased as object, and Java generics cannot be used for basic types.

Errorlist<int> A; 
What does the type erase mean?

First you have to understand that the type of an object will never be erased, for example, if you use an object to refer to an Apple object, you can still get its type. Like with Rtti.

Apple (); System.out.println (object.  GetClass ().  GetName (Apple     

Even if it is in a generic type.

Class bucket<t>{Private T T;public void set (T t) {this.t = T;} public T get () { Span class= "Hljs-keyword" >return THIS.T;} public void showclass () {System.out.println (T.getclass (). GetName ());}} bucket<apple> applebucket = new bucket<apple> (); AppleBucket.set (new Apple ()); Applebucket.showclass ();  # would print Apple too              

Why? Because the reference is a label that is used to access the object, the object has been placed on the heap.

So don't take it out of context that the type erase is to erase the type of object in the container, the so-called type wipe, refers to the container class Bucket<Apple> , for the Apple type declaration after the compilation period of the type check is erased, become and Bucket<Object> equivalent effect, it can be said and Bucket<Apple> Bucket<Banana> be wiped and c4/> is equivalent, not the type of the object itself is erased!

c#

C # combines the expansion of C + + with Java code sharing.

First, at compile time, C # will compile the generic Narimoto data, which is the IL assembly code that generates. NET. And when the CLR is running, the IL code is immediately compiled into the appropriate type of special code by JIT (instant compilation).

The benefit is that you will not generate multiple copies of code like C + +, and you will not lose the generic type like java. Basically do the best of both worlds.

So summarize the generics of c++,java,c#. C + + generics are fully expanded at compile time, with high type precision and poor shared code. Java generic use type wipe, only at compile time to do type check, wipe at run time, share code good, but type precision not. C # Generics use mixed implementations, expand at run time, have high type precision, and code sharing is good.

Why does Java have to be type-erased?

See here you may ask, why Java to use type erase such technology to achieve generics, and not as high as C #, is it because the Sun's group of people technology is far inferior to the group of Microsoft's people?

The reason is for backwards compatibility.

You go check history and you know that C # and Java do not support generics at first. To allow generics to be supported in a language that does not support generics, only two paths can go, either the previous non-generic containers remain unchanged, and then a set of generic types is added in parallel. Either extend the existing non-generic container directly to the generic type. No new generic versions are added.

At that time, C # from 1.1 to 2.0, the code is not many, and all in the Microsoft. NET controllable range, so chose the first implementation, you can actually find that there are two types of writing in C #, non-generic and generic notation:

New ArrayList (); //Generic list<list<int> ();   

Java's non-generic container, has been occupied from 1.4.2 to 5.0, the market already has a large number of code, forced to choose the second method. (The reason for this is from 1.4.2, because Java was not even collection before, is a kind of vector notation.) ), and there is one more important reason for the backward compatibility mentioned earlier. The so-called backwards compatibility is to ensure that 1.5 of the programs can also run on 8.0. (Of course, binary compatible, not source compatible.) So it is essentially intended to allow non-generic Java programs to run on subsequent JVMs that support generics.

So why use type erase to stay backwards compatible?

In the Java programming idea, in this example, the following two kinds of code is translated into Java Virtual machine sink encoding is the same, so whether it is the return type of the function is T, or your own initiative to write a strong turn, the end is to insert a checkcast statement:

Class simpleholder{PrivateObject obj;PublicObject Getobj () {return obj; }Publicvoid Setobj (object obj) {this.obj = obj;}} Simpleholder holder = new simpleholder (); Holder.setobj ( "Item" ); string s = (string) holder.getobj (); private T obj; public T getobj () {return obj;} public void setobj (T obj) { This.obj = obj; }}genericholder<string> holder = new GenericHolder <string> () holder.setobj ( "Item");  String s = holder.getobj ();              
Class java/lang/stringastore_2return

My image is understood as, before the non-generic writing, compiled by the virtual machine sink code block is a, after the generic style, just before a, "insert" the other sink code, and does not destroy the whole. This is considered to be non-generic "extended to generics", but also compatible with non-generics.

You should understand why Java uses type erase to implement generics. "And the pros and cons of this realization.

Java Learning Group 669823128

Why is Java using type erase to implement generics?

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.