了解上界和下界 ? 在 Java 泛型中
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19795709/
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
Understanding upper and lower bounds on ? in Java Generics
提问by Little Child
I am really having a tough time understanding the wild card parameter. I have a few questions regarding that.
我真的很难理解通配符参数。我有几个问题。
?
as a type parameter can only be used in methods. eg:printAll(MyList<? extends Serializable>)
I cannot define classes with?
as type parameter.I understand the upper bound on
?
.printAll(MyList<? extends Serializable>)
means: "printAll
will printMyList
if it has objects that implement theSerialzable
interface."
I have a bit of an issue with thesuper
.printAll(MyList<? super MyClass>)
means: "printAll
will printMyList
if it has objects ofMyClass
or any class which extendsMyClass
(the descendants ofMyClass
)."
?
作为类型参数只能在方法中使用。例如:printAll(MyList<? extends Serializable>)
我不能用?
as 类型参数定义类。我了解 的上限
?
。printAll(MyList<? extends Serializable>)
意思是:“如果它有实现接口的对象,printAll
就会打印MyList
出来Serialzable
。”
我对super
.printAll(MyList<? super MyClass>)
意思是:“如果它具有 的对象或任何扩展(的后代)的类,printAll
则将打印。MyList
MyClass
MyClass
MyClass
”
Correct me where I went wrong.
纠正我哪里出错了。
In short, only T
or E
or K
or V
or N
can be used as type parameters for defining generic classes. ?
can only be used in methods
总之,只有T
或E
或K
或V
或N
可以用作类型参数用于定义通用类。?
只能在方法中使用
Update 1:更新 1:
public void printAll(MyList<? super MyClass>){
// code code code
}
Accordint to Ivor Horton's book, MyList<? super MyClass>
means that I can print MyList
if it has objects of MyClass
or any of the interfaces or classes it implements. That is, MyClass
is a lower bound. It is the last class in the inheritance hierarchy. This means my initial assumption was wrong.
根据 Ivor Horton 的书,这MyList<? super MyClass>
意味着我可以打印MyList
它是否具有MyClass
它实现的对象或任何接口或类。也就是说,MyClass
是一个下界。它是继承层次结构中的最后一个类。这意味着我最初的假设是错误的。
So, say if MyClass
looks like:
所以,如果MyClass
看起来像:
public class MyClass extends Thread implements ActionListener{
// whatever
}
then, printAll()
will print if
1. There are objects of MyClass
in the list
2. There are objects of Thread
or ActionListener
in the List
然后,printAll()
将打印如果
1.MyClass
列表中
有对象 2. 有对象Thread
或ActionListener
在列表中List
Update 2:更新 2:
So, after having read the many answers to the question, here is my understanding:
因此,在阅读了该问题的许多答案后,这是我的理解:
? extends T
means any class which extendsT
. Thus, we are referring to the children ofT
. Hence,T
is the upper bound. The upper-most class in the inheritance hierarchy? super T
means any class / interface which issuper
ofT
. Thus we are referring to all the parents ofT
.T
is thus the lower bound. The lower-most class in the inheritance hierarchy
? extends T
表示任何扩展T
. 因此,我们指的是 的孩子T
。因此,T
是上限。继承层次结构中最上层的类? super T
指任何类/接口是super
的T
。因此,我们指的是 的所有父母T
。T
因此是下界。继承层次结构中最底层的类
采纳答案by Paul Bellora
?
as a type parameter can only be used in methods. eg:printAll(MyList<? extends Serializable>)
I cannot define classes with?
as type parameter.
?
作为类型参数只能在方法中使用。例如:printAll(MyList<? extends Serializable>)
我不能用?
as 类型参数定义类。
A wildcard (?
) isn't a formal type parameter, but rather can be used as a type argument. In the example you give, ? extends Serializable
is given as a type argument to the generic type MyList
, of the printAll
method's parameter.
通配符 ( ?
) 不是正式的类型参数,而是可以用作类型参数。在你给的例子,? extends Serializable
给出一个类型参数的泛型类型MyList
,该的printAll
方法的参数。
Methods can also declare type parameterslike classes, for example:
static <T extends Serializable> void printAll(MyList<T> myList)
I understand the upper bound on
?
.printAll(MyList<? extends Serializable>)
means printAll will print MyList if it has objects that implement the Serialzable interface
我了解 的上限
?
。printAll(MyList<? extends Serializable>)
意味着printAll 将打印 MyList 如果它具有实现 Serialzable 接口的对象
More accurately, it means a call to printAll
will compile only if it is passed a MyList
with some generic type that is or implements Serializable
. In this case it would accept a MyList<Serializable>
, MyList<Integer>
, etc.
更准确地说,这意味着只有在传递具有某种泛型类型为 或实现的 时,printAll
才会编译MyList
Serializable
。在这种情况下,它会接受MyList<Serializable>
,MyList<Integer>
等等。
I have a bit of an issue with the
super
.printAll(MyList<? super MyClass>)
means printAll will print MyList if it has objects of MyClass or any class which extends MyClass(the descendants of MyClass)
我对
super
.printAll(MyList<? super MyClass>)
意味着printAll 将打印 MyList 如果它有 MyClass 的对象或任何扩展 MyClass 的类(MyClass的后代)
A wildcard bounded with super
is a lowerbound. So we could say a call to printAll
will compile only if it is passed a MyList
with some generic type that is MyClass
or some super-type of MyClass
. So in this case it would accept MyList<MyClass>
, e.g. MyList<MyParentClass>
, or MyList<Object>
.
以super
为界的通配符是下界。因此,我们可以说调用printAll
,如果它传递一个只会编MyList
有一些通用的类型,它MyClass
还是一些超级型MyClass
。所以在这种情况下它会接受MyList<MyClass>
,例如MyList<MyParentClass>
, orMyList<Object>
。
So, say if MyClass looks like:
public class MyClass extends Thread implements ActionListener{ // whatever }
then, printAll() will print if
- There are objects of MyClass in the list
- There are objects of Thread or ActionListener in the list
所以,假设 MyClass 看起来像:
public class MyClass extends Thread implements ActionListener{ // whatever }
然后,printAll() 将打印如果
- 列表中有 MyClass 的对象
- 列表中有 Thread 或 ActionListener 的对象
You're on the right track. But I think saying e.g. "it will print if there are objects of MyClass
in the list" is problematic. That makes it sound like you're defining runtime behavior - generics are all about compile time checks. For example wouldn't be able to pass a MyList<MySubclass>
as an argument for MyList<? super MyClass>
, even though it might contain instances of MyClass
, by inheritance. I would reword it to:
你在正确的轨道上。但是我认为说例如“如果MyClass
列表中有对象,它将打印”是有问题的。这听起来像是在定义运行时行为 - 泛型都是关于编译时检查的。例如,无法通过继承将 aMyList<MySubclass>
作为 的参数传递MyList<? super MyClass>
,即使它可能包含 的实例MyClass
。我将其改写为:
A call to printAll(MyList<? super MyClass>)
will compile only if it is passed a:
调用printAll(MyList<? super MyClass>)
只有在传递了以下参数时才会编译:
MyList<MyClass>
MyList<Thread>
MyList<Runnable>
MyList<ActionListener>
MyList<EventListener>
MyList<Object>
MyList<? super X>
whereX
isMyClass
,Thread
,Runnable
,ActionListener
,EventListener
, orObject
.
MyList<MyClass>
MyList<Thread>
MyList<Runnable>
MyList<ActionListener>
MyList<EventListener>
MyList<Object>
MyList<? super X>
其中X
是MyClass
,Thread
,Runnable
,ActionListener
,EventListener
,或Object
。
So, after having read the many answers to the question, here is my understanding:
? extends T
means any class which extends T. Thus, we are referring to the children of T. Hence, T is the upper bound. The upper-most class in the inheritance hierarchy
? super T
means any class / interface which issuper
of T. Thus we are referring to all the parents of T. T is thus the lower bound. The lower-most class in the inheritance hierarchy
因此,在阅读了该问题的许多答案后,这是我的理解:
? extends T
表示任何扩展 T 的类。因此,我们指的是 T 的孩子。因此,T 是上限。继承层次结构中最上层的类
? super T
表示super
属于 T 的任何类/接口。因此我们指的是T 的所有父项。因此 T 是下限。继承层次结构中最底层的类
Close, but I wouldn't say "children of T
" or "parents of T
", since these bounds are inclusive- it would be more accurate to say "T
or its subtypes", and "T
or its supertypes".
关闭,但我不会说“孩子T
”或“父母T
”,因为这些界限是包含性的——说“T
或其子类型”和“T
或其超类型”会更准确。
回答by Hyman
First of all T
or E
or K
or whatever are not fixed names. They are just type variables, and you decide the name for them. T
, E
, K
are just examples but you could call it Foo
or whatever.
首先,T
or E
or K
or 什么都不是固定名称。它们只是类型变量,由您决定它们的名称。T
, E
,K
只是示例,但您可以调用它Foo
或其他什么。
Now going to your first question: since the wildcard ?
represents the "any and unknown" type, the unspecified one, it doesn't make any sense to declare a class generic over an unspecified type. It's useful to have wildcard in parameters of methods or in variables when you don't care about the type.
现在转到您的第一个问题:由于通配符?
表示“任何和未知”类型,即未指定的类型,因此在未指定的类型上声明泛型类没有任何意义。当您不关心类型时,在方法的参数或变量中使用通配符很有用。
Now regarding your second question: the lower bound gives even more flexibility to your generic methods. both extends
and super
are the opposite:
现在关于您的第二个问题:下限为您的通用方法提供了更大的灵活性。两者extends
和super
是相反:
? extends T
: an unknown type which is a subtype ofT
? super T
: an unknown type which is a super type ofT
? extends T
: 一个未知类型,它是T
? super T
: 一个未知类型,它是一个超类型T
The latter can be useful when you want to accept a type that is compatible with T (so that T is-a that type). A practical example can be found here.
当您想要接受与 T 兼容的类型(以便 T 是该类型)时,后者会很有用。可以在此处找到一个实际示例。
回答by Cyrille Ka
For the first question: you can not define a method with ?
as a type parameter either. The following will not compile:
对于第一个问题:您也不能将方法定义?
为类型参数。以下不会编译:
void <?> foo() {}
?
is used for binding to another generics without providing the type parameter. You can write for methods:
?
用于绑定到另一个泛型而不提供类型参数。您可以为方法编写:
void foo(List<?> e) {}
And you can also write for classes:
你也可以为类编写:
public class Bar<E extends List<?>> { }
For the use of super
:
用于super
:
public void printAll(MyList<? super MyClass>){
// code code code
}
This will not as you say print the list "if it has objects of MyClass". It can have objects of any class that is a subclass of a class that is a parent of MyClass. The compiler does not know at compile time what are the objects that will be in the list anyway.
这不会像你说的那样打印列表“如果它有 MyClass 的对象”。它可以拥有作为 MyClass 父类的子类的任何类的对象。编译器在编译时并不知道列表中的对象是什么。
To get your head around it, consider a simple example with the Number
class hierarchy. Float
and Integer
are children of Number
. You can write your method like this:
为了解决这个问题,请考虑一个带有Number
类层次结构的简单示例。Float
并且Integer
是 的孩子Number
。你可以这样写你的方法:
public void printAll(List<? super Float>){
// code code code
}
Then you can call that method with a List<Number>
:
然后您可以使用以下命令调用该方法List<Number>
:
List<Number> numbers = new ArrayList<>();
numbers.add(1); // actually only add an Integer
printAll(numbers); // compiles.
This is possible would not be super useful in that case. Where it would be useful for example is when you want to add Float
to a collection without wanting it to be only a List, like:
在这种情况下,这可能不会非常有用。例如,当您想要添加Float
到集合而不希望它只是一个列表时,它会很有用,例如:
public void addFloat(List<? super Float> list){
list.add(2.5);
}
回答by rolfl
Hmmmm your statement on super
( printAll(MyList<? super MyClass>)
) is not clear. What it means, assuming Myclass extends Object
is that you can printAll(MyList<MyClass>)
and you can printAll(MyList<Object>)
but nothing else.... it means that the generic type of MyList has to be a superclass (not a subclass) of MyClass. This is different to what you said.
嗯,你对super
( printAll(MyList<? super MyClass>)
)的陈述不清楚。这意味着,假设 Myclass 扩展Object
是你可以printAll(MyList<MyClass>)
,你可以,printAll(MyList<Object>)
但没有别的......这意味着 MyList 的泛型类型必须是 MyClass 的超类(而不是子类)。这和你说的不一样。
As for the T, E, K, V, or N, well, these are meaningless names in and of themselves. You can use anything you want. Convention suggests single-letter upper-case values though, and T is often used for generic methods, and E for classes....
至于 T、E、K、V 或 N,好吧,它们本身就是毫无意义的名称。你可以使用任何你想要的东西。约定建议使用单字母大写值,T 通常用于泛型方法,E 用于类......
回答by Boris the Spider
Lets start from the beginning.
让我们从头开始。
Strictly speaking any valid java identifiercan be used as a generic type parameter - it is just a special type of variable:
严格来说,任何有效的 java 标识符都可以用作泛型类型参数——它只是一种特殊类型的变量:
public static final class MyGenericClass<MyGenericType> {
}
Is perfectly valid Java.
是完全有效的 Java。
Next, you can use ?
anywhere where you can make a declaration. You can use the wildcard when you declare variables but not when you instantiatethem:
接下来,您可以?
在任何可以进行声明的地方使用。您可以在声明变量时使用通配符,但不能在实例化它们时使用:
public static final class MyGenericClass {
private final Collection<? extends String> myThings;
public MyGenericClass(Collection<? extends String> myThings) {
this.myThings = myThings;
}
public void doStuff(final Collection<? extends String> myThings) {
}
}
Is again all valid, you cannotdo this:
再次全部有效,您不能这样做:
final Collection<? extends String> myThings = new ArrayList<? extends String>();
When it comes to extends
vs super
this is called co-variance vs contra-variance. It determines which direction along the class hierarchy supplied types are allowed to travel:
当谈到extends
vs 时,super
这被称为协方差 vs 逆方差。它确定允许提供的类型沿类层次结构的哪个方向行进:
final Collection<? extends Runnable> example1 = new ArrayList<Runnable>();
final Collection<? extends Runnable> example2 = new ArrayList<TimerTask>();
final Collection<? super Runnable> example3 = new ArrayList<Runnable>();
final Collection<? super Runnable> example4 = new ArrayList<Object>();
The first two examples demonstrate extends
- the tightest bound you can assume from the Collection
is Runnable
as the user can pass a Collection
of anything that has Runnable
in its inheritance hierarchy.
前两个示例演示extends
- 您可以假设的最严格的界限Collection
是Runnable
因为用户可以传递其继承层次结构中Collection
的任何内容Runnable
。
The second two example demonstrate super
- the tightest bound you can assume from the Collection
is Object
as we allow anything that is inthe inheritance hierarchy of Runnable
.
第二个两个示例演示super
-最严格的约束,你可以假设从Collection
是Object
因为我们允许任何是在继承层次结构Runnable
。
回答by Ajay Kumar
Lower-bound says: You can use the class mentioned after 'super' keyword, or any of its super types. This can get tricky. Those super types may have other (completely different) classes inheriting from them, as below example shows.
下限表示:您可以使用在 'super' 关键字之后提到的类,或其任何超类型。这可能会变得棘手。这些超类型可能有其他(完全不同的)类继承自它们,如下例所示。
Say,
说,
List<? super Car> cars = new ArrayList <Vehicle>();
Should the programmer be allowed to write:
是否允许程序员编写:
cars.add(new Helicopter()); //Helicopter is a kind of Vehicle
That should obviously not be allowed, and it reflects a danger in using lower-bounds.
这显然不应该被允许,它反映了使用下限的危险。
Programmer should be allowed to add a Vehicle to list, but not ANY Vehicle. He must cast it, to let Java know he is only adding a Car Vehicle after all, like this:
应该允许程序员将车辆添加到列表中,但不能添加任何车辆。他必须投射它,让 Java 知道他毕竟只是添加了一辆 Car Vehicle,就像这样:
cars.add((Car) new Vehicle());