Search code examples
javaandroidgenericsnested-generics

Is there any point in <T extends View> in Android coding?


I tried to define a class that wraps android.view.View and its subclasses, and contains some info on rendering (people might call it as View Model or PresentationModel).

public class MyClass<T extends View>
{
    private T view;
    private Blah blah;     
}

My primal question is if I should make the type of the view variable parameterized or not. Java's Generic implementation seems to be rather simple (e.g. all the type parameter info is erased at compile time), and I can find two possible merits here.

1) Downcasting looks, say, cooler, even if I still have to specify the type somewhere in my codes.

@SuppressWarnings("unchecked")
public final <U extends View> U getView()
{
    return (U) view;
}

With above,

Button btn = (Button) obj.getView();
((LinearLayout) obj).addView(view);

becomes

Button btn = obj.getView();
obj.<LinearLayout>addView(view);

2) I may be able to write some polymorphic codes;

@Override
public void bringToFront()
{
    // stuff
}

If a method were redefined by some subclasses,

public final T getView()
{
    return view;
}

with above,

obj.bringToFront();

might behaves differently depending on the type parameter we gave. The biggest problem is I don't know if there is any actual override case in Google's android framework.

Currently, I'd avoid using Generics, since apparently I can't use HashMap with the generic class.

Map<String, MyClass<View>> objs = new HashMap<String, MyClass<View>>();
MtClass<Button> obj = objs.get(key);    // type mismatch    

Solution

  • 2) is incorrect, at least in your example. The function you provided is not polymorphic, so it would not be different based on T. Certainly sub-classes can redefine the behavior, but this has nothing to do with T.

    As to 1), yes it does make the code prettier, but it also makes it much unsafer. Considering you have the type of the view T, why are you casting it to a U? This is clearly illegal based on the code you have given above, and would be a compile-time error if you had not cast it, but now will just be a run-time error, unless the types happen to match up. I.e. if you had MyClass<Button> and defined T getView(), the code would work without casting it with U, or using the type parameter U at all, while MyClass<TextView> would cause a run-time error on getView(), despite the fact that it compiles correctly.

    As to your final point, when you retrieve an object from a Map<K, V> you can only prove that the object is a V, not a subtype of V, which is why your last example does not compile.

    Overall, generics are meant to increase code reuse while simultaneously enforcing type safety, however the examples you provided seem to only do the former, and throw type safety out the window (which to be fair, is what Android UI programming does in general). In the examples you have given, it does not appear that generics will help you more than it would hurt you.