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