Jon*_*an. 16 java generics interface
我有代码:
Set<? extends Notifiable> notifiables;
Run Code Online (Sandbox Code Playgroud)
通知是一个界面.我不明白上面的代码和之间的区别:
Set<Notifiable> notifiables;
Run Code Online (Sandbox Code Playgroud)
如果Notifiable是一个类,那么我就会理解它的区别,第一个代码将允许Notifiable和Notifiable的任何子类,而第二个代码只允许Notifiable(而不是任何子类)
由于您不能拥有接口实例,我可以在集合中添加/ etc?在我看来,只有两个选项,或者任何实现可通信的东西(在这种情况下,如何与第一个代码不同),或者只有"Notifiable"的实例,它们不存在,因此没有任何东西(这是毫无意义的应抛出编译时错误).
Wyz*_*a-- 15
A Set<Notifiable> 可以保存实现的类的实例Notifiable.它不仅仅限于持有具体类型的实例Notifiable(而且你是对的,没有这样的东西).但它Set<Notifiable>保证它可以包含任何类型Notifiable,因为它有一个add(Notifiable)方法可以接受任何实现接口的东西.
假设你有一些被调用的类Foo,Bar它们都实现了Notifiable.如果你创建一个Set<Foo>- 也就是说,一个只允许包含Foo其子类型的实例的集合- 你不能将它传递给一个带有a的方法Set<Notifiable>,因为该方法可能会添加非Foo实例的东西,例如Bar.
public void addABar(final Set<Notifiable> notifiables) {
notifiables.add(new Bar()); // OK, since Bar is a subtype of Notifiable
}
public void wontWork() {
final Set<Foo> foos = new HashSet<>();
addABar(foos); // Compile error, can't convert Set<Foo> to Set<Notifiable>
}
Run Code Online (Sandbox Code Playgroud)
但是有时候,你要编写一个方法可以接受的事情像Set<Foo>和Set<Bar>除Set<Notifiable>.这就是通配符的用武之地.A Set<? extends Notifiable>保证其中的所有内容都是某种形式Notifiable,但并不保证Notifiable可以添加任何类型的内容.允许将其限制为子类型.你不能调用add()它,因为现在这个方法add(? extends Notifiable)代替了add(Notifiable),你不能调用参数类型未知的方法.
您通常在不需要添加元素时使用它,但是您需要查看现有元素并Notifiable在其上调用接口方法,并且您希望允许调用者传递多个子类型集,例如Set<Foo>.
例如:
public void notifyAll(final Set<? extends Notifiable> notifiables) {
for (final Notifiable notifiable : notifiables) {
notifiable.notify();
}
}
public void example() {
final Set<Foo> foos = whatever();
notifyAll(foos); // OK, since a Set<Foo> is a Set<? extends Notifiable>
}
Run Code Online (Sandbox Code Playgroud)
如果notifyAll()拿了一个Set<Notifiable>,你将无法foos转移它.
让我们使用一个更直接的例子:
Set<? extends Serializable> serializables;
Run Code Online (Sandbox Code Playgroud)
这个声明了一个变量,它可以保存Set对Integers,Floats等的引用:
serializables = new HashSet<Serializable>(); // valid
serializables = new HashSet<Number>(); // this is valid as well
serializables = new HashSet<Integer>(); // valid
Run Code Online (Sandbox Code Playgroud)
另一方面这个:
Set<Serializable> serializables;
Run Code Online (Sandbox Code Playgroud)
只能容纳Set的Serializable对象但是:
serializables = new HashSet<Serializable>();
serializables = new TreeSet<Serializable>();
Run Code Online (Sandbox Code Playgroud)
所以这个将是一个编译器错误:
List<Serializable> numbers = new ArrayList<Integer>();
Run Code Online (Sandbox Code Playgroud)
推论:
如果你想要一个可以容纳任何子类型的 字段,Notifiable那么使用:
Set<Notifiable> notifiables = new HashSet<Notifiable>();
Run Code Online (Sandbox Code Playgroud)
如果你想限制Notifiable可以使用的子类型,那么这是要走的路:
Set<? extends Notifiable> notifiables = new HashSet<MyNotifiable>();
Run Code Online (Sandbox Code Playgroud)
附录:
这是完全合法的,因此您可以根据需要改进Set后期:
Set<? extends Notifiable> notifiables = new HashSet<NotifiableA>();
notifiables = new HashSet<NotifiableB>();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
625 次 |
| 最近记录: |