Generics to auto-cast and Use of instanceof with Generics


Using Generics to auto-cast

With generics, it's possible to return whatever the caller expects:

private Map<String, Object> data;
public <T> T get(String key) {
    return (T) data.get(key);
}

The method will compile with a warning. The code is actually more safe than it looks because the Java runtime will do a cast when you use it:

Bar bar = foo.get("bar");

It's less safe when you use generic types:

List<Bar> bars = foo.get("bars");

Here, the cast will work when the returned type is any kind of List (i.e. returning List<String> would not trigger a ClassCastException; you'd eventually get it when taking elements out of the list).

To work around this problem, you can create an API which uses typed keys:

public final static Key<List<Bar>> BARS = new Key<>("BARS");

along with this put() method:

public <T> T put(Key<T> key, T value);

With this approach, you can't put the wrong type into the map, so the result will always be correct (unless you accidentally create two keys with the same name but different types).


Use of instanceof with Generics

Using generics to define the type in instanceof

Consider the following generic class Example declared with the formal parameter <T>:

class Example<T> {
	public boolean isTypeAString(String s) {
		return s instanceof T; // Compilation error, cannot use T as class type here
	}
}

This will always give a Compilation error because as soon as the compiler compiles the Java source into Java bytecode it applies a process known as type erasure, which converts all generic code into non-generic code, making impossible to distinguish among T types at runtime. The type used with instanceof has to be reifiable, which means that all information about the type has to be available at runtime, and this is usually not the case for generic types.

The following class represents what two different classes of Example, Example<String> and Example<Number>, look like after generics has stripped off by type erasure:

class Example { // formal parameter is gone
    public boolean isTypeAString(String s) {
         return s instanceof Object; // Both <String> and <Number> are now Object
    }
}

Since types are gone, it's not possible for the JVM to know which type is T.

Exception to the previous rule

You can always use unbounded wildcard (?) for specifying a type in the instanceof as follows

public boolean isAList(Object obj) {
	return obj instanceof List<?>;
}

This can be useful to evaluate whether an instance obj is a List or not:

System.out.println(isAList("foo")); // prints false
System.out.println(isAList(new ArrayList<String>()); // prints true
System.out.println(isAList(new ArrayList<Float>()); // prints true

In fact, unbounded wildcard is considered a reifiable type.

Using a generic instance with instanceof

The other side of the coin is that using an instance t of T with instanceof is legal, as shown in the following example:

class Example<T> {
	public boolean isTypeAString(T t) {
		return t instanceof String; // No compilation error this time
	}
}

because after the type erasure the class will look like the following:

class Example { // formal parameter is gone
	public boolean isTypeAString(Object t) {
		return t instanceof String; // No compilation error this time
	}
}

Since, even if the type erasure happen anyway, now the JVM can distinguish among different types in memory, even if they use the same reference type (Object), as the following snippet shows:

Object obj1 = new String("foo"); // reference type Object, object type String
Object obj2 = new Integer(11); // reference type Object, object type Integer
System.out.println(obj1 instanceof String); // true
System.out.println(obj2 instanceof String); // false, it's an Integer, not a String

Different ways for implementing a Generic Interface (or extending a Generic Class)

Suppose the following generic interface has been declared

public interface MyGenericInterface<T> {
    public void foo(T t);
}

Below are listed the possible ways to implement it.

Non-generic class implementation with a specific type

Choose a specific type to replace the formal type parameter <T> of MyGenericClass and implement it, as the following example does:

public class NonGenericClass implements MyGenericInterface<String> {
     public void foo(String t) { } // type T has been replaced by String
}

This class only deals with String, and this means that using MyGenericInterface with different parameters (e.g. Integer, Object etc.) won't compile, as the following snippet shows:

NonGenericClass myClass = new NonGenericClass();
myClass.foo("foo_string"); // OK, legal
myClass.foo(11); // NOT OK, does not compile
myClass.foo(new Object()); // NOT OK, does not compile

Generic class implementation

Declare another generic interface with the formal type parameter <T> which implements MyGenericInterface, as follows:

public class MyGenericSubclass<T> implements MyGenericInterface<T> {
     public void foo(T t) { } // type T is still the same
     // other methods...
}

Note that a different formal type parameter may have been used, as follows:

public class MyGenericSubclass<U> implements MyGenericInterface<U> { // equivalent to the previous declaration
     public void foo(U t) { }
     // other methods...
}

Raw type class implementation

Declare a non-generic class which implements MyGenericInteface as a raw type (not using generic at all), as follows:

public class MyGenericSubclass implements MyGenericInterface {
    public void foo(Object t) { } // type T has been replaced by Object
    // other possible methods
}

This way is not recommended, since it is not 100% safe at runtime because it mixes up raw type (of the subclass) with generics (of the interface) and it is also confusing. Modern Java compilers will raise a warning with this kind of implementation, nevertheless the code - for compatibility reasons with older JVM (1.4 or earlier) - will compile.

All the ways listed above are also allowed when using a generic class as a supertype instead of a generic interface.

Basic Programs