loading gif

Generics limitations with Java

Author: Gokan EKINCI
First publication date: 2015-11-13
License: CC BY-NC-SA

Today I am going to present you some generics limitations with Java, for that I am going to show you some examples that you cannot realize in Java but you could do in other languages (in C++ and C#).

Java's generics allows you to do almost the same things than "templates" in C++ or "generics" in C#, but unlike C++ which is compiled (your types are replaced by real types at compile time, so theoretically the number of generated lines of code is increased but above the executable size is heavier), or in C# where types are known at Runtime (JIT), in Java we have cast operations at compile time.

Java and C# are 2 languages which are alike in many ways but generics in Java is based on "type erasure", whereas in C# on "reification".
There are many differences between those two mecanisms, I wouldn't hide that Java's generics has some limitations… Why ? Because generics has appeared very late (Java 5), and because of the will to keep compatibility with already existing Java libraries.

Unlike other languages, in Java you CANNOT:

Use primitive types (int, long, double etc):

List<int> list1 = new ArrayList<int>(); // Forbidden
List<Integer> list2 = new ArrayList<Integer>(); // OK

Why ? Short answer: Because primitive types are not castable with Object.

Instantiate a generic class:

public class MyClass1{
  T1 gen1; // OK
  MyClass1<T1> gen2; // OK
  MyClass2<Integer>[] gen3; // OK

  // Forbidden in Java, but possible in C++ (with templates), or C# with the new() constraint
  T1 gen4 = new T1(); 
  T1[] gen5 = new T1[10]; 
  MyClass2<Integer>[] gen6 = new MyClass2<Integer>[10]; 

There's a "tip" for making gen6 generic:

MyClass2<Integer>[] gen6 = ( MyClass2<Integer>[] ) new MyClass2[10];

Overload a generic method:

public void method(List<Foo> liste) { }

// Overloading attempt: forbidden in Java, possible in C++ and C#
public void method(List<Bar> liste){ }

Create a generic class which inherits from Exception class:

// Java
class MyException<T> extends Exception{   } // Forbidden

// C#
class MyException<T> : Exception{   } // OK

Use instanceof operator with your "T" generic type (even if T is covariant):

// Java
if(myObject instanceof T){ } // Error

// C#
if(myObject is T){ } // OK

Use class keyword (reflection) with generic types:

// Java
Class c = T.class; // Forbidden

// C# 
Type type = typeof(T); // OK

Java tip: Use Class<T> as a method parameter every time you need to use T.class inside a method, not convenient but effective.

To conclude, you can encounter the cases shown in my Java examples, however there is always (or almost) a way to find an alternative solution, like using Class<T> or instantiating an object then passing it through a method parameter.