一、如何理解泛型
泛型的本质是参数化类型。这句话怎么理解呢。就是说在一些需要使用类型的地方,不明确指定类型,而是使用一个参数,在实际使用时,通过传入的参数,指定具体使用哪个类型。
比如方法的入参,原本是必须指定参数类型的,但使用了泛型以后,就可以等到调用方法时才确定参数的类型。
二、为什么要使用泛型
泛型有以下几个好处:
- 保证了类型的安全性。 使用泛型后,如果集合中插入了错误类型的对象,可以在编译阶段就发现。未使用泛型时,要运行阶段才会报错。
List list = new ArrayList();
list.add(1);
String a = (String) list.get(0); // 运行时才报错
List<String > list2 = new ArrayList();
list2.add(1); // 编译阶段报错
- 消除强制转换
在没有泛型之前,从集合中读取到的每一个对象都默认为Object类型,故必须进行类型转换。使用泛型后可以省略此步骤。
- 避免了不必要的装箱、拆箱操作,提高程序的性能 泛型变量固定了类型,使用的时候就已经知道是值类型还是引用类型,避免了不必要的装箱、拆箱操作。所以运行效率相对较高,特别在对集合操作非常频繁的系统中,这个特点带来的性能提升更加明显。
public static void main(String[] args) {
int a = 1;
System.out.println(getValue(a)); // 导致装箱
System.out.println(getValueWithGenerics(a)); // 避免了装箱
}
public static Object getValue(Object o) {
return o;
}
public static <T> T getValueWithGenerics(T t) {
return t;
}
- 提高了代码的重用性。
如何使用泛型
泛型类
常见于类的构造函数中或成员变量需要使用泛型。
修饰符 class 类名 <泛型类型1,泛型类型2,...>
public class GenericsClass1<T> {
private T value;
GenericsClass1(T t) {
this.value = t;
}
public T getValue() {
return value;
}
public void print() {
System.out.println(getValue());
}
}
public static void main(String[] args) {
GenericsClass1<Integer> genericsClass1 = new GenericsClass1<>(123);
genericsClass1.print();
GenericsClass1<String> genericsClass2 = new GenericsClass1<>("456");
genericsClass2.print();
}
泛型类的子类有两种
- 指定了泛型类型的普通类
public class GenericsClass2 extends GenericsClass1<String> {
GenericsClass2(String s) {
super(s);
}
}
- 子类也是一个泛型类,子类的泛型类型,要等于或者多于父类的泛型类型
public class GenericsClass3<T, E> extends GenericsClass1<T> {
GenericsClass3(T t, E e) {
super(t);
}
}
注意异常类不能是泛型的
泛型接口
public interface 接口名<泛型类型>
public interface GenericsInterface1<T> {
public void printValue(T t);
}
泛型接口的实现有以下方式
- 实现时指定泛型类型
public class GenericsClass4 implements GenericsInterface1<String> {
public void printValue(String s) {
System.out.println("GenericsClass4 implements GenericsInterface1<String>");
System.out.println(s);
}
}
- 实现类也声明为泛型类
public class GenericsClass5<T> implements GenericsInterface1<T> {
@Override
public void printValue(T t) {
}
}
泛型函数
修饰符 <代表泛型> 返回值类型 函数名(参数){ }
泛型方法随着我们的传入参数类型不同,他得到的类型也不同。泛型方法能使方法独立于类而产生变化。
为什么要使用泛型方法呢?因为泛型类要在实例化的时候就指明类型,如果想换一种类型,不得不重新new一次,可能不够灵活;而泛型方法可以在调用的时候指明类型,更加灵活