Understanding Casting with Generics

With multiple level inheritance and polymorphism it can become a bit challenging to see how a method accepting and returning a generic would behave if within the method some transformation takes place and either a sub or super type of that generic is returned. Let’s take an example

Interface:

public interface ClassInterface {
    String sayHello();
}

Super-class:

public class ClassSuper implements ClassInterface {
    public String whoAmI = null;
    public ClassSuper() {
        whoAmI = "Super";
    }

    @Override
    public String sayHello() {
        return whoAmI + "says Hello!";
    }
}

Sub-class:

public class ClassSub1 extends ClassSuper {
    public ClassSub1() {
        whoAmI = "Sub1";
    }
}

Handler-class:

public class ClassHandler {
    public  T listenToOthers(T cls, String rType) {
        ClassInterface cls1 = ((ClassInterface) cls);
	cls1.sayHello();

	// test by returning different class
        if ("Sub".equals(rType)) {
            return (T) new ClassSub1();
	} else if ("Super".equals(rType)) {
	    return (T) new ClassSuper();
	} else {
	    return cls;
	}
    }

    public static void main(String[] args) {
        try {
	    System.out.println("passed-in: Sub1, requested: Same");
	    System.out.print("got: " + new ClassHandler().listenToOthers(new ClassSub1(), "Same").whoAmI);
	    System.out.println("\n");
			
	    System.out.println("passed-in: Super, requested: Sub");
	    System.out.print("got: " + new ClassHandler().listenToOthers(new ClassSuper(), "Sub").whoAmI);
	    System.out.println("\n");
			
	    System.out.println("passed-in: Sub1, requested: Super");
	    System.out.print("got: " + new ClassHandler().listenToOthers(new ClassSub1(), "Super").whoAmI);
	    System.out.println("\n");
        } catch (Exception e) {
	    e.printStackTrace();
	}
    }
}

Result:

passed-in: Sub1, requested: Same
got: Sub1

passed-in: Super, requested: Sub
got: Sub1

passed-in: Sub1, requested: Super
java.lang.ClassCastException: org.j2eebuilder.generics.ClassSuper cannot be cast to org.j2eebuilder.generics.ClassSub1
	at org.j2eebuilder.generics.ClassHandler.main(ClassHandler.java:29)

Explanation:
So what happened here?
1. We passed-in T=Sub1 and told handler to return the same (=Sub1), so T supplied = T returned. No issues!

2. We passed-in T=Super and told handler to return Sub1, so T supplied = super of T returned. Thus casting (T=Super) Sub1 (in the method listenToOthers) worked!

3. We passed-in T=Sub1 and told handler to return T=Super, so T supplied = sub (not super) of T returned. Thus casting (T=Sub1) Super (in the method listenToOthers) failed!

As you can see one might incorrectly think that I am passing in a sub-class and so getting back a super-class should be fine – though as explained it is not!

Hope it helps understand how generics work in complex inheritance and polymorphism scenarios!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s