Switch to full style
Java2 codes,problems ,discussions and solutions are here
Post a reply

How to use Generics in java

Sat Nov 08, 2008 10:04 am

How to use Generics in java is the topic of this article :
Unchecked Warning

The Java compiler will warn you if it can't verify type-safety. You would see this if you mix generic and non-generic code (which is not a good idea). Developing applications while leaving these kinds of warnings unattended is a risk. It is better to treat warnings as errors.

Consider the following example:



java code
public class Test
{
public static void foo1(Collection c)
{
}

public static void foo2(Collection<Integer> c)
{
}

public static void main(String[] args)
{
Collection<Integer> coll = new ArrayList<Integer>();
foo1(coll);

ArrayList lst = new ArrayList();
foo2(lst);
}
}


You have a method foo1 which accepts a traditional Collection as parameter. Method foo2, on the other hand, accepts a Generics version of the Collection. You are sending an object of the traditional ArrayList to method foo2. Since the ArrayList may contain objects of different types, within the foo2 method, the compiler is not able to guarantee that the Collection<Integer> will contain only instances of Integer. The compiler, in this case, issues a warning as shown below:
Warning: [unchecked] unchecked conversion found :
java.util.ArrayList required:
java code
java.util.Collection<java.lang.Integer>


While getting this warning is certainly better than not being alerted about the potential problem, it would have been better if it had been an error instead of a warning. Use the compilation flag Xlint to make sure you do not overlook this warning.

There is another problem. In the main method, you are sending a generic Collection of Integer to the method foo1. Even though the compiler does not complain about this, this is dangerous. What if within the foo1 method you add objects of types other than Integer to the collection? This will break the type-safety.

You may be wondering how in the first place the compiler even allowed you to treat a generic type as a traditional type. Simply put, the reason is, there is no concept of Generics at the byte code level. I will delve into the details of this in the "Generics Implementation" section.
Restrictions

There are a number of restrictions when it comes to using generics. You are not allowed to create an array of generic collections. Any array of collection of wildcards is allowed, but is dangerous from the type-safety point of view. You can't create a generic of a primitive type. For example, ArrayList<int> is not allowed. You are not allowed to create parametrized static fields within a generic class, or have static methods with parametrized types as parameters. For instance, consider the following:


java code
class MyClass<T>
{
private Collection<T> myCol1; // OK
private static Collection<T> myCol2; // ERROR
}

Within a generic class, you can't instantiate an object or an array of objects of a parametrized type. For instance, if you have a generic class MyClass<T>, within a method of that class, you can't write:

java code
new T();


or


java code
new T[10];


You may throw an exception of generic type; however, in the catch block, you have to use a specific type instead of the generic.

You may inherit your class from another generic class; however, you can't inherit from a parametric type. For instance, while:


java code
class MyClass2<T> extends MyClass<T>
{
}


is OK,


java code
class MyClass2<T> extends T
{
}


is not.

You are not allowed to inherit from two instantiations of the same generic type. For example, while:


java code
class MyList implements MyCollection<Integer>
{
//...
}


is OK,


java code
class MyList implements MyCollection<Integer>, MyCollection<Double>
{
//...
}

is not.

What is the reason for these restrictions? These restrictions largely arise from the way generics are implemented. By understanding the mechanism used to implement generics in Java, you can see where these restrictions come from and why they exist.
Generics Implementation

Generics is a Java language level feature. One of the design goals of Generics was to keep binary compatibility at the byte code level. By requiring no change to JVM, and maintaining the same format of the class files (byte code), you can easily mix Generics code and non-Generics code. However, this comes at a price. You may end up loosing what generics are intended to provide in the first place is type-safety.

Does it matter that generics are at the language level and not really at the byte code level? There are two reasons to be concerned. One, if this is only a language level feature, what would happen if and when other languages are expected to run on the JVM? If the other languages to run on JVM are dynamic languages (Groovy, Ruby, Python,¦), then it may not be a big deal. However, if you attempt to run a strongly typed language on JVM, this may be an issue. Second, if this is simply a language level feature (one heck of a macro essentially), then it would be possible to pass in correct types at runtime, using Reflection, for instance.

Unfortunately, Generics in Java does not provide adequate type-safety. It does not fully serve what it was created for.
Erasure

So, if Generics is a language level feature, what happens when you compile your Generics code? Your code is striped out of all parametric types, and each reference to a parametric type is replaced with a class (typically Object or something more specific). This process is given a fancy name type erasure.

According to the documentation: The main advantage of this approach is that it provides total interoperability between generic code and legacy code that uses non-parametrized types (which are technically known as raw types). The main disadvantages are that parameter type information is not available at run time, and that automatically generated casts may fail when inter operating with ill-behaved legacy code. There is, however, a way to achieve guaranteed run-time type safety for generic collections even when inter operating with ill-behaved legacy code.

While this provides interoperability with generic and non-generic code, it unfortunately compromises type-safety. Let's look at the effect of erasure on your code.

Consider the example code:



java code
class MyList<T>
{
public T ref;
}

By running javap, you can look at what is in the byte code as shown below:


java code
javap -c MyList
Compiled from "Test.java"
class com.agiledeveloper.MyList extends java.lang.Object{
public java.lang.Object ref;

com.agiledeveloper.MyList();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return

The type T of the ref member of the class has been erased to (replaced by) the type Object.

Not all types are always erased to or replaced by Object. Take a look at this example:


java code
class MyList<T extends Vehicle>
{
public T ref;
}

In this case, the type T is replaced by Vehicle as shown below:

java code
javap -c MyList
Compiled from "Test.java"
class com.agiledeveloper.MyList extends java.lang.Object{
public com.agiledeveloper.Vehicle ref;

com.agiledeveloper.MyList();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return


Now, consider the example:


java code
class MyList<T extends Comparable>
{
public T ref;
}

Here the type T is replaced by the Comparable interface.

Finally, if you use the multi-bound constraint, as in:

java code
class MyList<T extends Vehicle & Comparable>
{
public T ref;
}

then the type T is replaced by Vehicle. The first type in the multi-bound constraint is used as the type in erasure.
Effect of Erasure

Let is look at the effect of erasure on a code that uses a generic type. Consider the example:

java code
ArrayList<Integer> lst  = new ArrayList<Integer>();
lst.add(new Integer(1));
Integer val = lst.get(0);


This is translated into:



java code
ArrayList lst = new ArrayList();
lst.add(new Integer(1));
Integer val = (Integer) lst.get(0);


When you assign lst.get(0) to val, type casting is performed in the translated code. If you were to write the code without using generics, you would have done the same. Generics in Java, in this regards, simply acts as a syntax sugar.



Re: How to use Generics in java

Fri May 10, 2013 4:28 pm

updated.

Post a reply
  Related Posts  to : How to use Generics in java
 How to use Generics and implement it in Java     -  
 HashMap class with generics     -  
 2d game in java-Monster-Java 2D Game Graphics and Animation     -  
 What is Java API?!!!     -  
 java or .net     -  
 Using FTP in java     -  
 what is java     -  
 Java course     -  
 need help in java     -  
 Introduction to Java IO.pdf     -  

Topic Tags

Java Collections