1

我试图定义一个包装类 android.view.View及其子类,并包含一些有关渲染的信息(人们可能将其称为 View Model 或 PresentationModel)。

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

我的主要问题是我是否应该将视图变量的类型参数化。Java 的通用实现似乎相当简单(例如,所有类型参数信息在编译时都被删除),我可以在这里找到两个可能的优点。

1)向下转换看起来更酷,即使我仍然需要在代码中的某处指定类型。

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

有了上面,

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

变成

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

2)我也许可以写一些多态代码;

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

如果某个方法被某些子类重新定义,

public final T getView()
{
    return view;
}

与以上,

obj.bringToFront();

可能会根据我们提供的类型参数表现不同。最大的问题是我不知道 Google 的 android 框架中是否有任何实际的覆盖案例。

目前,我会避免使用泛型,因为显然我不能HashMap与泛型类一起使用。

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

1 回答 1

2

2)是不正确的,至少在你的例子中。您提供的函数不是多态的,因此基于T. 当然,子类可以重新定义行为,但这与T.

至于 1),是的,它确实使代码更漂亮,但也使它更不安全。考虑到您具有视图的类型T,为什么要将其转换为 a U?根据您上面给出的代码,这显然是非法的,如果您没有强制转换,这将是一个编译时错误,但现在只是一个运行时错误,除非类型碰巧匹配。即,如果您有MyClass<Button>并定义T getView()了 ,则代码可以在不使用 强制转换U或根本不使用类型参数U的情况下工作,同时MyClass<TextView>会在 上导致运行时错误getView(),尽管它可以正确编译。

至于您的最后一点,当您从 a 检索对象时,Map<K, V>您只能证明该对象是 a V,而不是 的子类型V,这就是您的最后一个示例无法编译的原因。

总体而言,泛型旨在增加代码重用,同时强制执行类型安全,但是您提供的示例似乎只做前者,并将类型安全抛到了窗外(公平地说,这是 Android UI 编程通常所做的)。在您给出的示例中,泛型对您的帮助似乎不会超过对您的伤害。

于 2013-01-10T05:17:24.223 回答