java笔记--泛型

126 阅读3分钟

一、如何理解泛型

泛型的本质是参数化类型。这句话怎么理解呢。就是说在一些需要使用类型的地方,不明确指定类型,而是使用一个参数,在实际使用时,通过传入的参数,指定具体使用哪个类型。

比如方法的入参,原本是必须指定参数类型的,但使用了泛型以后,就可以等到调用方法时才确定参数的类型。

二、为什么要使用泛型

泛型有以下几个好处:

  • 保证了类型的安全性。 使用泛型后,如果集合中插入了错误类型的对象,可以在编译阶段就发现。未使用泛型时,要运行阶段才会报错。
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一次,可能不够灵活;而泛型方法可以在调用的时候指明类型,更加灵活