0% found this document useful (0 votes)
34 views

Type Erasure Is Used in Java Generics. in The Interest of

Type erasure in Java generics removes all generic type information during compilation. After compilation, List<String> and List<Integer> are both treated as plain List objects. Generics were introduced to allow type-safe operations on collections by ensuring the types of objects added match the generic type of the collection. There are three main types of collections in Java: raw collections which allow any type of object; collections of type Object which are more restrictive than raw collections; and wildcard collections which represent a family of generic types. The choice between using <Number>, <? extends Number>, and <? super Number> depends on whether reading from or writing to the collection is needed. Generics allow user-defined classes to be parameterized over types

Uploaded by

Rajesh Manna
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
34 views

Type Erasure Is Used in Java Generics. in The Interest of

Type erasure in Java generics removes all generic type information during compilation. After compilation, List<String> and List<Integer> are both treated as plain List objects. Generics were introduced to allow type-safe operations on collections by ensuring the types of objects added match the generic type of the collection. There are three main types of collections in Java: raw collections which allow any type of object; collections of type Object which are more restrictive than raw collections; and wildcard collections which represent a family of generic types. The choice between using <Number>, <? extends Number>, and <? super Number> depends on whether reading from or writing to the collection is needed. Generics allow user-defined classes to be parameterized over types

Uploaded by

Rajesh Manna
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 13

Q1

What do you understand by the term type erasure with regards to

generics?
A1. The term type erasure is used in Java generics. In the interest of
backward compatibility, robustness of generics has been sacrificed through
type erasure. Type erasure takes place at compile-time. So, after compiling List
and List, both end up as List at runtime. They are both just lists.

1 List<String> myList = new ArrayList<String>( ); //in Java 6 and 7


2 List<String> myList = new ArrayList<>(); // In Java 8 can use empty <>
3

after compilation becomes backward compatible without any angular brackets.

1 List myList = new ArrayList( );


2

Java generics differ from C++ templates. Java generics (at least until JDK 8),
generate only one compiled version of a generic class or method regardless of
the number of types used. During compile-time, all the parametrized type
information within the angle brackets are erased and the compiled class file
will look similar to code written prior to JDK 5.0. In other words, Java does
not support runtime generics.

Q2. Why do you need generics?


A2. Generics was introduced in JDK 5.0, and allows you to abstract over
types. Without generics, you could put heterogeneous objects into a collection.
This can encourage developers to write programs that are harder to read and
maintain. For example,

1 List list = new ArrayList( );


2 list.add(new Integer( ));
3 list.add(A String);
4 list.add(new Mango( ));
5

As demonstrated above, without generics you can add any type of object to a
collection. This means you would not only have to use instanceof operator,
but also have to explicitly cast any objects returned from this list. The code is
also less readable. The following code with generics is not only more readable,

1 List<String> list1 = new ArrayList<String>( );


2 List<Integer> list2 = new ArrayList<Integer>( );
3

but also throws a compile time error if you try to add an Integer object to list1
or a String object to list2.

Q3.

What are the differences among?

Raw or plain old collection type e.g. Collection


Collection of unknown e.g. Collection<?>
Collection of type object e.g. Collection<Object>

A3.

1) The plain old Collection: is a heterogeneous mixture or a

mixed bag that contains elements of all types, for example Integer, String,
Fruit, Vegetable, etc.
2) The Collection<object>: is also a heterogeneous mixture like the
plain old Collection, but not the same and can be more restrictive than a plain
old Collection discussed above. It is incorrect to think of this as the super type
for a collection of any object types.
Unlike an Object class is a super type for all objects like String, Integer, Fruit,
etc, List<Object> is not a super type for List<String>, List<Integer>,
List<Fruit>, etc. So it is illegal to do the following:

1 List<Object> list = new ArrayList<Integer>( );//illegal


2

Though Integer is a subtype of Object, List is not a subtype of List<Object>


because List of Objects is a bigger set comprising of elements of various types
like Strings, Integers, Fruits, etc. A List of Integer should only contain
Integers, hence the above line is illegal. If the above line was legal, then you
can end up adding objects of any type to the list, violating the purpose of
generics.
3) The Collection<?>: is a homogenous collection that represents a
family of generic instantiations of Collection like Collection<String>,
Collection<Integer>, Collection<Fruit>, etc.
Collection<?> is the super type for all generic collection as Object[ ] is the
super type for all arrays.

Number class hierachy

1 List<?> list = new ArrayList<Integer>( );

//legal

2 List<? extends Number> list = new ArrayList<Integer>( ); //legal


3

Q4.

How will you go about deciding which of the following to use?

1) <Number>
2) <? extends Number>
3) <? super Number>

A4.

Many developers struggle with the wild cards. Here is the guide:

1. Use the ? extends wildcard if you need to retrieve object from a data
structure. That is read only. You cant add elements to the collection.
2. Use the ? super wildcard if you need to put objects in a data structure.
3. If you need to do both read and add elements, dont use any wildcard.

Q5.

What does the following code fragment print?

1
2 List<String> list1 = new ArrayList<String>( );
3 List<Integer> list2 = new ArrayList<Integer>( );
4 System.out.println(list1.getClass( ) == list2.getClass( ));
5

A5 It prints true because of type erasure(i.e. Rule 1), all instances of a


generic class have the same runtime class, regardless of their actual type
parameter. This also mean, there is no sense in checking generic information
at runtime. The following code is illegal.

1 if(list1 instanceof List<String>) //illegal


2

Q6.

Is the following line legal? If not, how will you fix it?

1
2 List<Object> list = new ArrayList<Integer>( );
3

A6. It is Illegal because Unlike an Object class is a super type for all objects
like String, Integer, Fruit, etc, List&l;tObject> is not a super type for
List<String>, List<Integer>, List<Fruit>, etc. List<?> is the super type.

1
2 List<?> list = new ArrayList<Integer>( );
//legal
3 List<? extends Number> list = new ArrayList<Integer>( );
//legal
4

Note:<? extends Number> is read only and <?> is almost read only allowing
only removce( ) and clear ( ) operations.
The Collection<?> can only be used as a reference type, and you cannot
instantiate it.

1 List<?> fruitBasket = new ArrayList<?>( ); //illegal


2 List<?> fruitBasket = new ArrayList<? extends Fruit>( ); //illegal
3

Q7.
A7

How will you generify your own Java class?

1
2 public class MyGenericClass<T> {
3
4
T objType;
5
6
public MyGenericClass(T type) {
7
this.objType = type;
8
}

9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
}
2
2
2
3
2
4
2
5
2
6

public T getObjType( ) {
return objType;
}
public void setObjType(T objType) {
this.objType = objType;
}
public static void main(String[ ] args) {
MyGenericClass<Integer> val1 = new MyGenericClass<Integer>(37);
MyGenericClass<Long> val2 = new MyGenericClass<Long>(250L);
long result = val1.getObjType( ).longValue( ) +
val2.getObjType( ).longValue( );
System.out.println(result);
}

If you decompile the converted class file, you will get,

1 public class MyGenericClass<T>


2 {
3
T objType;
4
5 public MyGenericClass(T type)
6 {
7
this.objType = type;
8 }
9
1 public T getObjType( ) {
0
return this.objType;
1 }
1
1 public void setObjType(T objType) {
2
this.objType = objType;
1 }
3

1
4
1
5
1
6
1
7
public static void main(String[ ] args) {
1
MyGenericClass val1 = new MyGenericClass(Integer.valueOf(37));
8
MyGenericClass val2 = new MyGenericClass(Long.valueOf(250L));
1
long result = ((Integer)val1.getObjType( )).longValue( ) +
9
((Long)val2.getObjType( )).longValue( );
2
System.out.println(result);
0
}
2
}
1
2
2
2
3
2
4
2
5

//auto-box
//auto-box

If you closely examine the above code, you would notice that the compiler has
performed auto-boxing as generics does not support primitive types. The angle
brackets have been removed for val1 & val2 declarations and appropriate
castings have been added to convert from type T to Integer and Long types.

Q8. What do you understand by the term type argument inference?


A8. The type inference happens when the compiler can deduce the type
arguments of a generic type or method from a given context information.
There are 2 situations in which the type argument inference is attempted
during compile-time.
1. When an object of a generic type is created as demonstrated in the
MyGenericClass<T>.

1
2 //T is inferred as an Integer
3 MyGenericClass<Integer> val1 = new MyGenericClass<Integer>(37);
4 //T is inferred as a Long
5 MyGenericClass<Long> val2 = new MyGenericClass<Long>(250L);
6

2. When a generic method is invoked. For example,

1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
3

import java.util.ArrayList;
import java.util.List;
public class MyBasket {
/**
* The 'src' is the inferred type T or its sub type and the 'dest' is the
* inferred type T or its super type.
*/
public static <T> void copy(List<? extends T> src, List<? super T> dest) {
for (T obj : src) {
dest.add(obj);
}
}
public static void main(String[] args) {
List<Orange> orangeBasket = new ArrayList<Orange>(10);
List<Mango> mangoBasket = new ArrayList<Mango>(10);
orangeBasket.add(new Orange());
mangoBasket.add(new Mango());
List<Fruit> fruitBasket = new ArrayList<Fruit>(10);
List<Orange> orangeBasket2 = new ArrayList<Orange>(10);
orangeBasket2.add(new Orange());
List<Mango> mangoBasket2 = new ArrayList<Mango>(10);
mangoBasket2.add(new Mango());
List<Fruit> fruitBasket2 = new ArrayList<Fruit>(10);
fruitBasket2.add(new Mango());
MyBasket.copy(orangeBasket2, orangeBasket);
MyBasket.copy(mangoBasket2, mangoBasket);

// T is an Orange
// T is a Mango

MyBasket.<Orange> copy(orangeBasket, fruitBasket); // T is an Orange


MyBasket.<Mango> copy(mangoBasket, fruitBasket);
// T is a Mango
MyBasket.copy(fruitBasket2, fruitBasket);
for (Fruit fruit : fruitBasket) {
fruit.peel();
}
}
}

// T is a Fruit

2
3
3
3
4
3
5
3
6
3
7
3
8
3
9
4
0
4
1
4
2
4
3
4
4
4
5

The copy() method ensures that fruits from a mixed fruit basket cannot be
copied to a basket that only holds oranges or mangoes. But a mixed fruit
basket allows fruits to be copied from any basket.

Q9.

Is the following code snippet legal? If yes why and if not why not?

1
2 public MyGenericClass( ) {
3
this.objType = new T( );
4}
5

A9. It is not legal as new T( ) will cause a compile-time error. This is partially
because theres no guarantee that the target class for raw type T has a
constructor that takes zero parameters and partially due to type erasure where
the raw type T does not have any way of knowing the type of object you want
to construct at runtime.

Q10. Is it possible to generify methods in Java?


A10. Yes.

1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3

import java.util.ArrayList;
import java.util.List;
public class MyGenericMethod {
//Generified method
public static <T> void addValue(T value, List<T> list){//Line A
list.add(value);
}
public static void main(String[ ] args) {
List<Integer> listIntegers = new ArrayList<Integer>( );
Integer value1 = new Integer(37);
addValue(value1, listIntegers);
//T is inferred as an Integer
System.out.println("listIntegers=" + listIntegers);
List<String> listString = new ArrayList<String>( );
String value2 = "Test";
addValue(value2, listString);
//T is inferred as a String
System.out.println("listString=" + listString);
}
}

Note: If you had used the wildcard List<?> instead of List<T> on line A, it
would not have been possible to add elements. You will get a compile-time
error. So how does the compiler know the type of T? It infers this from your
use of the method. The generated class file looks pretty much the same as the
source file without the <Integer> and <String> angle brackets

Q11.

Does the following code snippet compile? What does it demonstrate?

2
3
4 public class Generics4<T> {
5
6
public <T> void doSomething(T data) {
7
System.out.println(data);
8
}
9
1
public static void main(String[ ] args) {
0
Generics4<String> g4 = new Generics4<String>( );
1
g4.doSomething(123);
1
}
1 }
2
1
3

A11. Yes, the above code snippet does compile. It demonstrates that the
type parameter in the class name and the type parameter in the method are
actually different parameters. The method signature,

1
2
3

public <T> void doSomething(T data)

really means,

1
2 public void doSomething(Object data)
3

Q12.

1
2
3
4
5
6

Can you identify any issues with the following code?

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class GenericsWithIterators {

7
8
9
1
0
1
1
1
public static void main(String[ ] args) {
2
List<Integer> listIntegers = new ArrayList<Integer>( );
1
listIntegers.add(5); //2
3
listIntegers.add(3); //3
1
4
Iterator it = listIntegers.listIterator( ); //4
1
5
while(it.hasNext( )){ //5
1
Integer i = it.next( ); //6
6
System.out.println(i); //7
1
}
7
}
1
}
8
1
9
2
0
2
1
2
2

//1

A12.
Line 4 will cause compile-time error on line 6 as the iterator is not generic. To
fix this, replace line 4 with:

1
2 Iterator<Integer> it = listIntegers.listIterator( ); // fix 1
3

or add an explicit cast to line 6.

1
2 Integer i = (Integer) it.next( );// fix 2

The fix 1 is preferred. When you get an iterator, keyset, or values from a
collection, assign it to an appropriate parametrized type as shown in fix 1.

You might also like