如果我有ArrayList<Shape>
,我的印象是在该列表中我可以存储类Shape
的对象或Shape
的子类。
我也看到很多关于ArrayList<T>
或ArrayList<?>
等内容的注释。这些都是一样的吗?可以存储T
超类及其所有子类,而?
只是一个占位符?
基本上,ArrayList<CLASSNAME>
之类的内容与{1}}的区别在于您只有一个字母。
答案 0 :(得分:1)
首先,区别在于它是否是您想象的一个字母。是T
是否是通用参数的名称。如果您声明一个类似的方法:
public <T> void method()
而不是:
public void method()
或类似:
public class Whatever<T>
而不是:
public class Whatever
然后T
是一个通用参数。然后,您可以在任何您想要的地方使用T
,就好像它是一个真正的类名,并且在编译时将使用真实的类名替换T
。但这不是它的最佳图片,所以让我们说T
的类型是传递给类型T的参数的任何类型。因此,在任何给定时刻,T
都有一个值是一个真实的类名。
因此,ArrayList<T>
和ArrayList<Shape>
之间的区别在于ArrayList<T>
包含T
类型的对象,而ArrayList<Shape>
包含Shape
类型的对象}。诀窍是T
是传递给类型T
的参数的任何类型,因此它可以变化。
免责声明:类型T
实际上并未随时间而变化。在大多数情况下,编译器将其替换为Object
。但是,编译器擅长隐藏它,并且考虑T
更改是个好主意。
答案 1 :(得分:1)
首先,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类中的String替换T.
顺便说一句,你不应该使用T作为参数的类型。因为T没有真正定义,所以它只是一个占位符。
答案 2 :(得分:0)
当您在声明类型/类时表达ArrayList<T>
,在创建ArrayList实例时表达ArrayList<String>
并将其与类型参数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) { .. }
}