目前,我正在准备考试,我将在两天内写完。 在示例问题中,我发现了以下问题:
这会编译吗?
FavoritesList<Person> l = new FavoritesList<Contact>();
(联系人延伸人)
我会回答是,因为如果我有以下内容:
FavoritesList<Person> l = new FavoritesList<Person>();
l.add(new Contact());
没关系。为什么在第一个例子中不是很好?
请记住:联系人延伸人!
提前致谢 最好的问候
答案 0 :(得分:2)
这是禁止的,但让我指出为什么:
让我们考虑一下:
FavoritesList<Person> l = new FavoritesList<Contact>();
FavoritesList<Person>
允许执行但FavoritesList<Contact>
禁止的操作,即添加Person
的任何子类,这些子类违反了FavoritesList<Contact>
的合同。
您可能正在寻找的是:
FavoritesList<? extends Person> wildcardedList = new FavoritesList<Contact>();
表示:这是一个未指定类型?
的列表,此列表中的所有元素都属于此类型?
,我们知道此类型?
正在扩展人员。请注意,此类型通配符最初可能不直观。基本上他们给你的是这个列表的只读视图。
让我们假设:
class FavoritesList<T>{
void add(T t){...}
}
基本上你不能打电话:
wildcardedList.add(new Contact());
也不:
wildcardedList.add(new Contact());
因为我们不知道Person
或Contact
是否为未指定的类型T.
要做到这一点,你必须在add
参数的类型中添加通配符,然后它就会变得混乱。
答案 1 :(得分:1)
这不好,因为Java中的泛型不支持继承,这意味着FavoritesList<Contact>
不是FavoritesList<Person>
的子类型
请参阅:http://docs.oracle.com/javase/tutorial/java/generics/inheritance.html
答案 2 :(得分:0)
不,它不会起作用。 Java不提供泛型的协方差属性,因此如果Contact扩展Person,这并不意味着FavoritesList<Contact>
扩展FavoritesList<Person>
。
答案 3 :(得分:0)
想象一下,你有另一个Person的子类(例如Enemy,Enemy扩展Person)。
然后,如果第一个被允许,你可以这样做:
FavoritesList<Contact> contacts = // a list of some Contacts
FavoritesList<Person> l = contacts;
// at this point, contacts and l both reference the same object!
l.add(new Enemy()); // allowed by the compiler since enemy is a person
// now contacts contains an enemy which is bad since Enemy is not a Contact!
Contact c = contacts.get(contacts.size() - 1); // would throw a class cast exception if the compiler allowed the above
请注意,Java确实为通配符提供了解决方法,因此您可以这样做:
FavoritesList<Contact> contacts = // a list of some Contacts
FavoritesList<? extends Person> l = contacts;
Person person = l.get(0); // ok since we know everything in l is some class that extends Person
l.add(new Enemy()); // won't compile, since we can't verify that Enemy is the ?
答案 4 :(得分:0)
这不好,因为允许它允许您将其他类型的Person
插入Contact
列表中。虽然Contact
s'的不可变列表确实是Person
s的“不可变列表”,但Contact
s的可变列表是{{1}的可变列表是不正确的。 s - 您可以将非Person
插入Contact
的可变列表中,但不能插入Person
s的可变列表中。
因此,出于安全考虑,Java禁止您执行此类操作。你能做的就是这样:
Contact
这是有效的,因为您无法通过FavoritesList<? extends Person> l = new FavoritesList<Contact>();
插入非Contact
并打破您的列表。
其他语言(例如C#,Scala)允许您为类型参数提供协方差和逆变量注释,以便更好地控制在这种情况下允许的转换(例如,如果是,则可以将类型参数标记为协变允许FavoritesList<? extends Person>
转换为Thing<Derived>
),但Java不会。这是一个关于这个主题的C#参考,可能会让事情更清晰:
http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx
答案 5 :(得分:0)
在FavoritesList<Person> l = new FavoritesList<Contact>();
{}创建了FavoritesList
的{{1}}。
但是通过引用Contact
,您将能够添加任何类型的FavoritesList<Person> l
类或扩展Person的类的实例,例如let Person
到该列表。
你认为这样会安全吗?
答案 6 :(得分:0)
有一个原因是它不能编译,可以用数组来观察。
Object[] objects = new String[10];
objects[0] = new Object();
现在每条线都是有道理的。但是我们最终将一个Object插入一个String数组中,这当然是错误的并抛出异常。
随后添加的泛型和java开发人员决定解决此问题,List<String>
与List<Object>
不兼容,因为两者对其内容有不同的约束,但是他们添加了一个额外的语法,所以{{1} 1}}与List<String>
兼容(读取:可包含未知类型对象的列表)。
List<? extends Object>