我对Java泛型如何处理继承/多态性感到困惑.
假设以下层次结构 -
动物(父母)
狗 - 猫(儿童)
所以假设我有一个方法doSomething(List<Animal> animals).根据所有继承和多态的规则,我会假设a List<Dog> 是 a List<Animal>而a List<Cat> 是 a List<Animal>- 所以任何一个都可以传递给这个方法.不是这样.如果我想实现这种行为,我必须明确告诉该方法接受一个Animal的任何子类的列表doSomething(List<? extends Animal> animals).
我知道这是Java的行为.我的问题是为什么?为什么多态通常是隐含的,但是当涉及泛型时必须指定它?
让我们首先考虑一个简单的场景(请参阅ideone.com上的完整源代码):
import java.util.*;
public class TwoListsOfUnknowns {
static void doNothing(List<?> list1, List<?> list2) { }
public static void main(String[] args) {
List<String> list1 = null;
List<Integer> list2 = null;
doNothing(list1, list2); // compiles fine!
}
}
Run Code Online (Sandbox Code Playgroud)
这两个通配符是不相关的,这就是为什么你可以doNothing用a List<String>和a 调用List<Integer>.换句话说,两者?可以指代完全不同的类型.因此,以下不编译,这是预期的(也在ideone.com上):
import java.util.*;
public class TwoListsOfUnknowns2 {
static void doSomethingIllegal(List<?> list1, List<?> list2) {
list1.addAll(list2); // DOES NOT COMPILE!!!
// The method addAll(Collection<? extends capture#1-of ?>)
// in the type List<capture#1-of …Run Code Online (Sandbox Code Playgroud) 为什么我super只能使用通配符而不使用类型参数?
例如,在Collection界面中,为什么toArray方法不是这样写的
interface Collection<T>{
<S super T> S[] toArray(S[] a);
}
Run Code Online (Sandbox Code Playgroud) 我几天前从未听说过野猫,在读完老师的Java书后,我仍然不确定它是什么,为什么我需要使用它.
比方说,我有一个超类Animal和几个子类,如Dog,Cat,Parrot,等...现在我需要有动物名单,我首先想到的会是这样的:
List<Animal> listAnimals
Run Code Online (Sandbox Code Playgroud)
相反,我的同事们推荐的内容如下:
List<? extends Animal> listAnimals
Run Code Online (Sandbox Code Playgroud)
为什么我应该使用通配符而不是简单的泛型?
假设我需要一个get/set方法,我应该使用前者还是后者?他们怎么这么不同?
我有两个嵌套泛型的类.有没有办法摆脱
类型不匹配:无法转换Msg<Value<String>>为Msg<Value<?>>错误?在最后一次任务中
public class Value<V> {
V val;
public Value(V val) {
this.val = val;
}
@Override
public String toString() {
return "" + val;
}
}
public class Msg<T> {
T holder;
public Msg( T holder) {
this.holder = holder ;
}
public String toString() {
return "" + holder;
}
public static void main(String[] args) {
Msg<Value<String>>strMsg = new Msg(new Value<String>("abc"));
// This is OK
Msg<?>objMsg = strMsg;
// Type mismatch: cannot convert from …Run Code Online (Sandbox Code Playgroud) 这么奇怪!请先查看代码:
public class A {}
public class B extends A {}
public class C extends A {}
public class TestMain {
public <T extends A> void test(T a, T b) {}
public <T extends A> void test(List<T> a, List<T> b) {}
public void test1(List<? extends A> a, List<? extends A> b) {}
public static void main(String[] args) {
new TestMain().test(new B(), new C());
new TestMain().test(new ArrayList<C>(), new ArrayList<C>());
new TestMain().test(new ArrayList<B>(), new ArrayList<C>());
new TestMain().test1(new ArrayList<B>(), new ArrayList<C>());
}
} …Run Code Online (Sandbox Code Playgroud) 我今天遇到了这种奇怪的(在我看来)行为.拿这个简单的Test类:
public class Test {
public static void main(String[] args) {
Test t = new Test();
t.run();
}
private void run() {
List<Object> list = new ArrayList<Object>();
list.add(new Object());
list.add(new Object());
method(list);
}
public void method(Object o) {
System.out.println("Object");
}
public void method(List<Object> o) {
System.out.println("List of Objects");
}
}
Run Code Online (Sandbox Code Playgroud)
它的行为与您期望的一样,打印"对象列表".但是如果你改变以下三行:
List<String> list = new ArrayList<String>();
list.add("");
list.add("");
Run Code Online (Sandbox Code Playgroud)
你会得到"对象".
我尝试了其他一些方法并获得了相同的结果.这是一个错误还是正常行为?如果这是正常的,有人可以解释为什么吗?
谢谢.
比方说,我有一个班级:
public class MyFoo : IMyBar
{
...
}
Run Code Online (Sandbox Code Playgroud)
然后,我想使用以下代码:
List<MyFoo> classList = new List<MyFoo>();
classList.Add(new MyFoo(1));
classList.Add(new MyFoo(2));
classList.Add(new MyFoo(3));
List<IMyBar> interfaceList = new List<IMyBar>(classList);
Run Code Online (Sandbox Code Playgroud)
但这会产生错误:
`Argument '1': cannot convert from 'IEnumerable<MyFoo>' to 'IEnumerable<IMyBar>'
Run Code Online (Sandbox Code Playgroud)
为什么是这样?由于MyFoo实现了IMyBar,人们可以预期IEnumerable的MyFoo可以被视为IMyBar的IEnumerable.一个平凡的现实世界的例子是生产汽车列表,然后被告知它不是车辆列表.
这只是一个小小的烦恼,但如果有人能够对此有所了解,我会非常感激.
尽管String实现了CharSequence,但Java不允许这样做.这个设计决定的原因是什么?
我有一个Animal.Class和Dog类,它扩展了Animal.Class
我可以知道是否有一种快速简便的方法吗?
List<Dog> dogList = getAnimalList();
public List<Animal> getAnimalList(){
List<Animal> animalList = new LinkedList<Animal>();
return animalList;
}
Run Code Online (Sandbox Code Playgroud)
除非绝对必要,否则我不希望再看整个动物名单.
dog类只包含一个额外的布尔值以用于其他检查目的.
generics ×9
java ×9
inheritance ×2
wildcard ×2
c#-3.0 ×1
casting ×1
collections ×1
covariance ×1
ienumerable ×1
polymorphism ×1
super ×1