免责声明:我不是一名专业开发人员,我不打算成为一名专业开发人员。关于Java的阅读书,因为我想尝试Android编程,没有任何以前的Java经验。
我正在阅读this book - 我更喜欢它。我已经阅读了关于泛型类的章节的一部分,到了他们提到通配符的地步,并且感到困惑。
如果B延伸A:
List<B>
不是 List<A>
的子类型(据我了解,它们完全相同)List<? extends B>
是List<? extends A>
后者允许编写接受泛型类型参数的函数 - 例如List<? extends A>
。这样的函数会接受List<B>
或List<A>
的参数。
现在,我的问题是:
以类似于C ++的方式(以“模板”的方式)实现泛型不是更简单吗?这会使List<B>
和List<A>
两种不同的类型,这些类型会以预期的方式相关联。这也可以简单地在一个函数中声明你期望一个参数是List<A>
类型,这样就可以让List<B>
适合那里。
我猜不仅仅是“我们讨厌C ++,让我们做出与众不同的事情”背后这个:)我很可能还不知道什么,这使得通配符变得非常棒和有用的工具。你对此有何看法?
修改:如果您在答案中提及List<X>
,请记住使用反引号,以避免将<X>
解释为HTML标记。
答案 0 :(得分:5)
原因很简单。
假设您有一个List<A>
类型的变量。假设List<B>
确实是List<A>
的子类型。
这意味着当这是合法的时候:
List<A> a_list;
a_list = new List<B>(); //allowed when List<B> is subtype of list<A>
a_list.add(new A()); // WOAH!
在我说WOAH时,会发生以下情况:您将a类型的项目添加到a_list。由于a_list被声明为List<A>
,因此这应该是合法的。但是等一下:a_list指的是List<B>
类型的东西。
所以现在我们在列表中添加类型A的东西,它应该只存储B类的项目,这显然不是我们想要的,因为A不是B的子类!
答案 1 :(得分:1)
如果List&lt; B&gt;是List&lt; A&gt;的子类型。以下代码是合法的,因为java确实在编译时删除了大部分Generic魔法。 (如果这是一个好的决定或不是一个不同的主题)。
public void addNewAToList(List<A> list) {
list.add(new A());
}
public static void main(String[] args) {
List<B> listB = new LinkedList<B>();
addNewAToList(listB); // <--- compiler error
for (B b : listB) { // <--- otherwise: there is an A in the list.
System.out.println(b);
}
}
答案 2 :(得分:0)
问题在于,如果您有class C extends A
并且获得了List<A>
,则可以C
加入C
,因为A
是List<B>
。但是,如果Java允许您只给C
方法,那么您将B
放在C
列表中。并且B
不是null
,因此会出现错误。 Java的通配符解决方案不允许您向List<? extends A>
添加除{{1}}之外的任何内容,从而避免出现此错误。
答案 3 :(得分:0)
好吧,Comeau c++ online compiler对此失败了:
template<typename T> class List {
};
class A {
};
class B: public A {
};
void function(List<A> listA) {
}
int main(int argc, char** argv) {
List<A> a;
List<B> b;
function(a);
function(b);
}
发出此错误:
"ComeauTest.c", line 18: error: no suitable user-defined conversion from "List<B>" to
"List<A>" exists
function(b);
因此,在处理这些类型时,C ++和Java是相似的。
答案 4 :(得分:0)
静态类型表明子类型必须支持其超类型的所有操作。
List<Fruit>
支持插入Fruit
个对象。
List<Banana>
没有 - 您不能将任意水果插入List<Banana>
,只能插入香蕉。
因此,List<Banana>
不是List<Fruit>
的子类型。