Difference between revisions of "Generics"

From Suhrid.net Wiki
Jump to navigationJump to search
Line 3: Line 3:
 
* '''WHY Type erasure ?''' To ensure backward compatibility with legacy code.
 
* '''WHY Type erasure ?''' To ensure backward compatibility with legacy code.
 
* This compile-time safety is broken when generic and non-generic legacy code are mixed up.
 
* This compile-time safety is broken when generic and non-generic legacy code are mixed up.
 +
 +
See below:
 +
 +
<syntaxhighlight lang="java5">
 +
      private void bar() {
 +
List<Integer> li = new ArrayList<Integer>();
 +
li.add(new Integer(1));
 +
li.add(new Integer(2));
 +
foo(li);
 +
for(Integer i : li) {
 +
System.out.println(i.intValue()); // This will fail with a ClassCastException.
 +
}
 +
}
 +
 +
private static void foo(List l) {
 +
l.add(new Integer(3));
 +
l.add(new String("4")); //Compiler ALLOWS this !  However, warning will be generated.
 +
}
 +
 +
</syntaxhighlight>
  
 
* Watch out when autoboxing is involved with legacy code.
 
* Watch out when autoboxing is involved with legacy code.

Revision as of 03:30, 31 May 2011

  • Generics is a way to enforce ONLY compile-time type safety.
  • All the type information is not present at run-time. The compiler strips out type information from the bytecode using a process called type erasure.
  • WHY Type erasure ? To ensure backward compatibility with legacy code.
  • This compile-time safety is broken when generic and non-generic legacy code are mixed up.

See below:

       private void bar() {
		List<Integer> li = new ArrayList<Integer>();
		li.add(new Integer(1));
		li.add(new Integer(2));
		foo(li);
		for(Integer i : li) {
			System.out.println(i.intValue()); // This will fail with a ClassCastException.
		}
	}
	
	private static void foo(List l) {
		l.add(new Integer(3));
		l.add(new String("4")); //Compiler ALLOWS this !  However, warning will be generated.
	}
  • Watch out when autoboxing is involved with legacy code.
List l = new ArrayList();
l.add(123); //Auto-boxing happens.
int i = l.get(0); //Compile-time error. Autounboxing cant work because get() returns Object and not Integer.


Polymorphism and Generics

List<String> list = new ArrayList<String>();

Polymorphism only applies to the base type i.e list can be declared as arraylist You CANNOT do this:

 List<Animal> obj = new ArrayList<Dog>(); //NOT POSSIBLE

WHY ?

To prevent scenarios where you cannot add say, a Cat object to a Dog List. If the above conversion were possible it will be possible to do so. See below:

//NOTE : This is not possible actually, because the compiler prevents it.
public void foo() {
   List<Dog> dList = new ArrayList<Dog>();
   addAnimal(dList); //Compiler flags an error here. a Dog list cannot be assigned to an Animal list
}

private void addAnimal(List<Animal> aList) {
  aList.add(new Cat());
}

However, the SAME thing is possible with Arrays

public void foo() {
   Dog[] dA = new Dog[]{};
   addAnimal(dList); 
}

private void addAnimal(Animal[] aa) {
  aa[0] = new Cat(); //This will cause a runtime ArrayStoreException
}
  • The reason why it such polymorphism is possible with Arrays but not with collections is because of Type Erasure.
  • Since there is no type information at run-time, JVM cannot raise an exception.
  • This will be exactly the same problem when type-safe collections are mixed with non-type safe ones.
  • So, the compiler will prevent such polymorphic assignments when we are dealing with type-safe collections.