Generics (泛型)
概念:
- 泛型是参数多态性在java中的表现。参数多态性是指方法针对多种类型时具有同样的行为 (这里的多种类型具有通用的结构),此时可使用统一的类型表达多种类型 。
- 泛型编程是一种编程风格,其中数据类型和函数是根据待 指定的类型编写的,随后在需要时根据参数提供的特定类型进行实例 化。
- 泛型编程围绕“从具体进行抽象”的思想,将采用不同数据表示的 算法进行抽象,得到泛型化的算法,可以得到复用性、通用性更强 的软件。
使用
使用占位符<>,使用菱形运算符,用于帮助声明类型变量。
泛型类
格式:
class ClassName<T, E,…> {
private T var;
.....
}
类中如果声明了一个或多个泛型变量,则为泛型类。这些类型变量称为类的类型参数 。
- 它定义了一个或多个充当参数的类型变量。
- 泛型类声明定义了一组参数化类型。
- 所有这些参数化类型在运行时共享同一个类。
示例:
public class PapersJar<T> {
public static void main(String args[]) {
PapersJar<String> papersStr = new PapersJar<>();
papersStr.add("Lion");
String str = papersStr.get(0);
System.out.println(str);
PapersJar<Integer> papersInt = new PapersJar<>();
papersInt.add(new Integer(100));
Integer integerObj = papersInt.get(0);
System.out.println(integerObj);
}
private List<T> itemList = new ArrayList<>();
public void add(T item) {
itemList.add(item);
}
public T get(int index) {
return (T) itemList.get(index);
}
}
其中T为泛型
泛型接口
格式:
interface InterfaceName<T,E,…>{
public T methodName();
.....
}
- 它定义了一个或多个充当参数的类型变量。
- 泛型接口声明定义了一组类型,每种类型都可以调用。
- 所有参数类型在运行时共享相同的接口。
例子:java的 Set<E>作为泛型接口,定义如下:
抽象方法:
由于接口不能实例化,我们必须有一个具体类来完成接口。
使用普通类完成
(这里只重写了几个方法作为示例,完整的需要重写接口中所有方法。其中checkRep是在检查ADT的表示不变性)
使用泛型类完成
泛型方法
格式:
public <T> T genericMethod(Class<T> tClass) {
T instance = tClass.newInstance();
...
return instance;
}
方法是否为泛型方法不取决于方法的参数,而是看方法有没有在定义中声明使用泛型(下图的位置处声明)
class Generic2Test<T> {
// 下面的T同所在类的类型变量一致,show1不是泛型方法
public void show1(T t) {
System.out.println(t.toString());
}
//下面的E是新的类型变量,只适用于此方法,show2是泛型方法 (此处如果没有前面的<E>会报错)
public <E> void show2(E t) {
System.out.println(t.toString());
}
//下面的T是新的类型变量(虽然名字一样,但是同类的类型变量T无关。不过IDE会产生警告)
// show3是泛型方法
public <T> void show3(T t) {
System.out.println(t.toString());
}
}
上述代码调用格式:
public static void main(String[] args) {
Generic2Test<String> genericTest = new Generic2Test<>();
genericTest.show1("genericTest!"); //成功, "genericTest!"
genericTest.show1(Integer.valueOf("1")); //编译失败
genericTest.show2(Integer.valueOf("1")); //成功, 1
genericTest.show3(Integer.valueOf("1")); //成功, 1
}
注意
- 泛型类/接口,是在实例化类的时候指明泛型的具体类型(类型擦除); 泛型方法,是在调用方法的时候指明泛型的具体类型。
- 静态方法 不能使用所在泛型类定义的泛型变量 。 如果静态方法要使用泛型的话,必须将静态方法也定义成泛型方法 。
- 可以使用通配符(如List<?> ),这里不详述了。
- Java中的泛型是不“型变”的 。如
– ArrayList<String> 是List<String> 的子类
– List<String> 不是List<Object>的子类 - 由于编译的时候会类型擦除,故不要使用instanceof 检查泛型类型
- 泛型不能创建数组