Chapter: Java The Complete Reference - The Java Language - Generics

| Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail |

Erasure - Java

Usually, it is not necessary to know the details about how the Java compiler transforms your source code into object code.

Erasure

 

Usually, it is not necessary to know the details about how the Java compiler transforms your source code into object code. However, in the case of generics, some general understanding of the process is important because it explains why the generic features work as they do— and why their behavior is sometimes a bit surprising. For this reason, a brief discussion of how generics are implemented in Java is in order.

An important constraint that governed the way that generics were added to Java was the need for compatibility with previous versions of Java. Simply put, generic code had to be compatible with preexisting, non-generic code. Thus, any changes to the syntax of the Java language, or to the JVM, had to avoid breaking older code. The way Java implements generics while satisfying this constraint is through the use of erasure.

In general, here is how erasure works. When your Java code is compiled, all generic type information is removed (erased). This means replacing type parameters with their bound type, which is Object if no explicit bound is specified, and then applying the appropriate casts (as determined by the type arguments) to maintain type compatibility with the types specified by the type arguments. The compiler also enforces this type compatibility. This approach to generics means that no type parameters exist at run time. They are simply a source-code mechanism.

Bridge Methods

 

Occasionally, the compiler will need to add a bridge method to a class to handle situations in which the type erasure of an overriding method in a subclass does not produce the same erasure as the method in the superclass. In this case, a method is generated that uses the type erasure of the superclass, and this method calls the method that has the type erasure specified by the subclass. Of course, bridge methods only occur at the bytecode level, are not seen by you, and are not available for your use.

Although bridge methods are not something that you will normally need to be concerned with, it is still instructive to see a situation in which one is generated. Consider the following program:

 

 

// A situation that creates a bridge method.

class Gen<T> {

 

T ob; // declare an object of type T

 

     //Pass the constructor a reference to an object of type T.

 

Gen(T o) { ob = o;

 

}

 

// Return ob.

T getob() { return ob;

 

}

 

}

 

// A subclass of Gen.

 

class Gen2 extends Gen<String> {

 

Gen2(String o) { super(o);

 

}

 

// A String-specific override of getob().

String getob() {

 

System.out.print("You called String getob(): "); return ob;

 

}

 

}

 

// Demonstrate a situation that requires a bridge method.

class BridgeDemo {

 

public static void main(String args[]) {

 

// Create a Gen2 object for Strings.

Gen2 strOb2 = new Gen2("Generics Test");

 

System.out.println(strOb2.getob());

 

}

 

}

In the program, the subclass Gen2 extends Gen, but does so using a String-specific version of Gen, as its declaration shows:

 

class Gen2 extends Gen<String> {

 

Furthermore, inside Gen2, getob( ) is overridden with String specified as the return type:

 

// A String-specific override of getob().

String getob() {

 

System.out.print("You called String getob(): "); return ob;

 

}

 

All of this is perfectly acceptable. The only trouble is that because of type erasure, the expected form of getob( ) will be

 

Object getob() { // ...

 

To handle this problem, the compiler generates a bridge method with the preceding signature that calls the String version. Thus, if you examine the class file for Gen2 by using javap, you will see the following methods:

 

class Gen2 extends Gen<java.lang.String> {

Gen2(java.lang.String);

 

java.lang.String getob();

java.lang.Object getob(); // bridge method

}

 

As you can see, the bridge method has been included. (The comment was added by the author and not by javap, and the precise output you see may vary based on the version of Java that you are using.)

There is one last point to make about this example. Notice that the only difference between the two getob( ) methods is their return type. Normally, this would cause an error, but because this does not occur in your source code, it does not cause a problem and is handled correctly by the JVM.

 

Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail


Copyright © 2018-2020 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.