java java中的简单通用列表
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1132985/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
simple generic list in java
提问by andersonbd1
Why are java generics so tricky? I thought I finally understood, but eclipse gives me an error at the line in somOtherMethod below using either of the getOuterList methods below.
为什么java泛型如此棘手?我以为我终于明白了,但是 eclipse 使用下面的任一 getOuterList 方法在下面的 somOtherMethod 中给了我一个错误。
protected List<?> getOuterList() {
// blah blah
}
protected List<? extends Object> getOuterList() {
// blah blah
}
protected void someOtherMethod() {
...
getOuterList().add((MyObject)myObject); //compile error
...
}
UPDATE: ok - so I understand the error now. It was lack of understanding on my part of what List<?>or List<? extends SomeObject>really means. In the former case, I thought it meant a list that could contain anything. In the latter case, I assumed it was a list of a bunch of objects that extend SomeObject. The proper representation of my understanding would just be List<Object>and List<SomeObject>(w/out the extends). I thought extends helped me solve a problem which they don't. So here's where my real problem lies:
更新:好的 - 所以我现在明白这个错误了。我对什么List<?>或List<? extends SomeObject>真正意味着什么缺乏了解。在前一种情况下,我认为这意味着一个可以包含任何内容的列表。在后一种情况下,我假设它是一组扩展 SomeObject 的对象的列表。我的理解的正确表示就是List<Object>和List<SomeObject>(没有扩展)。我认为扩展帮助我解决了他们没有的问题。所以这就是我真正的问题所在:
public interface DogKennel {
public List<Dog> getDogs();
}
public class GreyHoundKennel implements DogKennel {
protected List<GreyHound> greyHounds;
public List<GreyHound> getGreyHounds() {
return this.greyHounds;
}
public List<Dog> getDogs() {
// Is there no way to handle this with generics
// w/out creating a new List?
return getGreyHounds(); //compiler error
}
}
采纳答案by Bob Cross
You're tripping over the fact that Java generics are not polymorphic on the type parameter.
您被 Java 泛型在类型参数上不是多态的事实绊倒了。
Talking through your code fragment, let's pull the example apart:
讨论您的代码片段,让我们将示例分开:
protected List<GreyHound> greyHounds; // List<GreyHound> is fine
/** This method returns a lovely List of GreyHounds */
public List<GreyHound> getGreyHounds() {
return this.greyHounds;
}
/** Here is the problem. A List<GreyHound> is not a List<Dog> */
public List<Dog> getDogs() {
return getGreyHounds(); //compiler error
}
So your original comment is correct. The two Lists are definitely different with no inheritance between them. So, I would suggest that you investigate these two options:
所以你原来的评论是正确的。这两个 List 绝对不同,它们之间没有继承。所以,我建议你调查这两个选项:
Try returning a new list as you suggest in your comment. For example,
return new ArrayList<Dog>(this.greyHounds);Do you really need to keep a list of a specific breed of Dog? Perhaps you should define the data member to be a
List<Dog>to which you add your specific GreyHounds. I.e.,protected List<Dog> greyHoundsOnly;where you manage which dogs are allowed in the kennel via the object's external interface.
尝试按照您在评论中的建议返回一个新列表。例如,
return new ArrayList<Dog>(this.greyHounds);您真的需要保留特定品种的狗的清单吗?也许您应该将数据成员定义为
List<Dog>您添加特定 GreyHounds 的 a 。即,protected List<Dog> greyHoundsOnly;您可以通过对象的外部接口管理哪些狗可以进入狗窝。
Unless you have a good reason to keep a type-specific list, I would think seriously about option 2.
除非您有充分的理由保留特定于类型的列表,否则我会认真考虑选项 2。
EDIT: fleshing out my suggested options above:
编辑:充实我上面的建议选项:
Option 1: Return a new list. Pros: Simple, straightforward, you get a typed list out and it eliminates a thread-safety problem (doesn't expose an internal reference to the world). Cons: seemingly a performance cost.
选项 1:返回一个新列表。优点:简单、直接,你得到一个类型化的列表,它消除了线程安全问题(不向世界公开内部引用)。缺点:似乎是性能成本。
// Original code starts here.
public interface DogKennel {
public List<Dog> getDogs();
}
public class GreyHoundKennel implements DogKennel {
protected List<GreyHound> greyHounds;
public List<GreyHound> getGreyHounds() {
return this.greyHounds;
}
// Original code ends here
public List<Dog> getDogs() {
// This line eliminates the thread safety issue in returning
// an internal reference. It does use additional memory + cost
// CPU time required to copy the elements. Unless this list is
// very large, it will be hard to notice this cost.
return new ArrayList<Dog>(this.greyHounds);
}
}
Option 2: Use a different data representation. Pros: plays nicer with polymorphism, returns the generic list that was the original goal. Cons: it's a slightly different architecture which may not fit with the original task.
选项 2:使用不同的数据表示。优点:多态性更好,返回原始目标的通用列表。缺点:它的架构略有不同,可能不适合原始任务。
public abstract class DogKennel {
protected List<Dog> dogs = new ArrayList<Dog>();
}
public class GreyHoundKennel extends DogKennel {
// Force an interface that only allows what I want to allow
public void addDog(GreyHound greyHound) { dogs.add(greyHound); }
public List<Dog> getDogs() {
// Greatly reduces risk of side-effecting and thread safety issues
// Plus, you get the generic list that you were hoping for
return Collections.unmodifiableList(this.dogs);
}
}
回答by newacct
You are saying that the method returns a "Listof some unknown type" (which you can't add to, because you can't guarantee that the thing you are adding is a subtype of that type). You actually want to say, a "Listof whatever type you want", so you have to make the method generic:
您是说该方法返回“List某种未知类型”(您无法添加,因为您无法保证您添加的内容是该类型的子类型)。您实际上想说“List您想要的任何类型”,因此您必须使该方法通用:
protected <T> List<T> getOuterList() {
// blah blah
}
Okay, I just looked at your update:
好的,我刚刚看了你的更新:
It all depends on what you intend to be able to do with the result of getDogs(). If you do not intend to be able to add any items to the list, then getDogs()should return type List<? extends Dog>, and then the problem would be solved.
这一切都取决于您打算对getDogs(). 如果您不打算将任何项目添加到列表中,getDogs()则应返回 type List<? extends Dog>,然后问题将得到解决。
If you intend to be able to add things to it, and by the type List<Dog>it means that you can add any kind of Dogto it, then logically this list cannot be the same list as greyHounds, because greyHoundshas type List<GreyHound>and so Dogobjects should not go in it.
如果您打算向其中添加内容,并且类型List<Dog>意味着您可以向其中添加任何类型的Dog内容,那么从逻辑上讲,此列表不能与 列表相同greyHounds,因为greyHounds具有类型List<GreyHound>,因此Dog不应将对象放入其中.
Which means that you must create a new list. Keeping in mind of course that any changes to the new list would not be reflected in the original list greyHouds.
这意味着您必须创建一个新列表。请记住,对新列表的任何更改都不会反映在原始列表中greyHouds。
回答by Ogre Psalm33
This declaration:
本声明:
List<?> getOuterList() { }
is telling the compiler "I really don't know what kind of list I'm going to get back". Then you essentially execute
告诉编译器“我真的不知道我要取回什么样的列表”。然后你基本上执行
list<dunno-what-this-is>.add((MyObject)myObject)
It can't add a MyObject to the List of something that it doesn't know what type it is.
它不能将 MyObject 添加到它不知道它是什么类型的东西的列表中。
This declaration:
本声明:
protected List<? extends Object> getOuterList() { ... }
tells the compiler "This is a list of things that are subtypes of Object". So again, of course you can't cast to "MyObject" and then add to a list of Objects. Because all the compiler knows is that the list can contain Objects.
告诉编译器“这是一个对象的子类型列表”。再说一次,当然你不能投射到“MyObject”然后添加到对象列表中。因为编译器只知道列表可以包含对象。
You couldhowever, do something like this:
但是,您可以执行以下操作:
List<? super MyObject>.getOuterList() { ... }
and then successfully add a MyObject. That's because now the compiler knows the List is a list of MyObject, or any supertype of MyObject, so it can surely accept MyObject.
然后成功添加了一个MyObject。那是因为现在编译器知道 List 是 MyObject 的列表,或者 MyObject 的任何超类型,所以它肯定可以接受 MyObject。
Edit:As for your DogKennel example, this code snippet I think does what you want:
编辑:至于您的 DogKennel 示例,我认为此代码片段可以满足您的需求:
protected List<GreyHound> greyHounds;
// We only want a List of GreyHounds here:
public List<GreyHound> getGreyHounds() {
return this.greyHounds;
}
// The list returned can be a List of any type of Dog:
public List<? extends Dog> getDogs() {
return getGreyHounds();
}
回答by 01es
There is already an accepted answer, however, pls consider the following code modification.
已经有一个可接受的答案,但是,请考虑以下代码修改。
public interface DogKernel {
public List<? extends Dog> getDogs();
}
public class GreyHoundKennel implements DogKernel {
protected List<GreyHound> greyHounds;
public List<GreyHound> getGreyHounds() {
return this.greyHounds;
}
public List<? extends Dog> getDogs() {
return getGreyHounds(); // no compilation error
}
public static void main(String[] args) {
GreyHoundKennel inst = new GreyHoundKennel();
List<? extends Dog> dogs = inst.getDogs();
}
}
Java generics are indeed broken, but not that broken. BTW Scala fixes this in a very elegant way by providing variance handling.
Java 泛型确实被破坏了,但并没有那么严重。顺便说一句,Scala 通过提供差异处理以一种非常优雅的方式解决了这个问题。
UPDATE ----------
更新 - - - - -
Please consider an updated snippet of code.
请考虑更新的代码片段。
public interface DogKennel<T extends Dog> {
public List<T> getDogs();
}
public class GreyHoundKennel implements DogKennel<GreyHound> {
private List<GreyHound> greyHounds;
public List<GreyHound> getDogs() {
return greyHounds; // no compilation error
}
public static void main(String[] args) {
GreyHoundKennel inst = new GreyHoundKennel();
inst.getDogs().add(new GreyHound()); // no compilation error
}
}
回答by james
a generic type of ? means "some specific type, but i don't know which". anything using a ? is essentially read-only because you can't write to it w/out knowing the actual type.
的通用类型?意思是“某种特定类型,但我不知道是哪种”。任何使用 ? 本质上是只读的,因为您无法在不知道实际类型的情况下写入它。

