如果我有ArrayList<Shape>
,我的印象是在该列表中我可以存储类Shape
的对象或作为Shape
.
我还看到了很多类似ArrayList<T>
or的符号ArrayList<?>
。这些是一样的吗?T
可以存储超类及其所有子类,而只是?
一个占位符?
基本上,类似的东西与你只有一个字母的地方有什么ArrayList<CLASSNAME>
不同。ArrayList<T>
如果我有ArrayList<Shape>
,我的印象是在该列表中我可以存储类Shape
的对象或作为Shape
.
我还看到了很多类似ArrayList<T>
or的符号ArrayList<?>
。这些是一样的吗?T
可以存储超类及其所有子类,而只是?
一个占位符?
基本上,类似的东西与你只有一个字母的地方有什么ArrayList<CLASSNAME>
不同。ArrayList<T>
首先,区别不在于它是否像您想象的那样是一个字母。它是否T
是通用参数的名称。如果您声明如下方法:
public <T> void method()
相对于:
public void method()
或类似的课程:
public class Whatever<T>
相对于:
public class Whatever
thenT
是一个通用参数。然后,您可以在任何您想要的地方使用它,就好像它是一个真实的类名一样,并且在编译时T
将替换一个真实的类名。T
但这不是最好的描述,所以假设T
类型是传递给类型 T 的参数的任何类型。因此,在任何给定时刻,T
都有一个真正的类名值。
ArrayList<T>
因此,和之间的区别在于ArrayList<Shape>
它ArrayList<T>
持有 type 的对象T
,而ArrayList<Shape>
持有 type 的对象Shape
。诀窍在于T
将任何类型传递给 type 的参数T
,因此它可以变化。
免责声明:类型T
实际上不会随着时间而改变。在大多数情况下,编译器会将其替换为Object
. 但是,编译器擅长隐藏这一点,考虑T
更改是个好主意。
首先,ArrayList 不能像这样引用 Shape 的任何子类:
ArrayList<Shape> blah = new ArrayList<Square>
但是你可以这样做:
ArrayList<? extends Shape> blah = new ArrayList<Square>
多态性不适用于类型参数。它仅适用于以下对象:
Collection<String> blah = new ArrayList<String>
但是你必须了解使用T的目的。T用于为类和方法声明类型参数。
这样当你声明一个带有参数 T 的类时:
public class ArrayList <T>
当类被实例化为对象时,T 充当占位符。
所以在这种情况下:
ArrayList<String>
您在 ArrayList 类中将 T 替换为 String 。
顺便说一句,您不应该使用 T 作为参数的类型。因为 T 没有真正定义,它只是一个占位符。
您ArrayList<T>
在声明类型/类以及ArrayList<String>
创建 ArrayList 实例并将其与类型参数 String 关联时表达。
例如:
// class declaration
public class ArrayList<T> extends ... implements ... {
...
// Creating an arraylist of string
ArrayList<String> stringArray = new ArrayList<String>
您可以将泛型视为类型变量。因此,不要创建一个仅适用于 String 的类:
public class MyArray {
String get(int index) { ... }
}
您可以创建一个适用于任意类型的数组类
public class MyArray<T> {
T get(int index) { .. }
}