您的位置:

Java泛型

一、引言

泛型是Java中的一项重要特性,使得Java代码可以更加类型安全,灵活性更高。本文将从基础概念、泛型类、泛型方法、通配符、类型擦除、泛型与继承、泛型与数组等方面进行详细阐述。

二、基础概念

1、泛型概述

泛型是Java从JDK1.5引入的一项功能,它可以允许程序员在编写程序时对类型进行参数化。使用泛型的好处是可以在编译时检测出类型错误,避免在运行时抛出异常。而没有使用泛型的程序则需要进行强制类型转换,使得代码更加冗长且难以理解。

2、泛型类

泛型类指在定义时可以使用参数的类。通过使用类定义时声明的泛型参数,可以在类中的方法和属性中使用这些参数。例如:

public class Box<T> {
    private T t;

    public void set(T t) {
        this.t = t;
    }

    public T get() {
        return t;
    }
}

上面这个Box类是一个泛型类,使用了一个类型参数T。因此当创建Box对象时,需要在类名后跟上尖括号,用来传递类中使用的具体类型。例如:

Box<String> box = new Box<>();
box.set("Hello");
System.out.println(box.get());

注意,这里使用了Diamond语法,即尖括号中不需要再重复声明类型参数。另外,泛型类可以使用多个类型参数,例如:

public class Pair<T, U> {
    private T first;
    private U second;

    public Pair(T first, U second) {
        this.first = first;
        this.second = second;
    }

    public T getFirst() {
        return first;
    }

    public U getSecond() {
        return second;
    }
}

3、泛型方法

泛型方法指在定义时可以使用参数的方法。通过使用方法定义时声明的泛型参数,可以在方法中使用这些参数。例如:

public <T> void printArray(T[] array) {
    for (T element : array) {
        System.out.print(element + " ");
    }
}

上面这个printArray方法是一个泛型方法,使用了类型参数T。因此在调用该方法时,需要在方法名前声明类型参数。例如:

Integer[] intArray = { 1, 2, 3 };
String[] stringArray = { "Hello", "World" };

printArray(intArray);
printArray(stringArray);

三、进阶概念

1、通配符

通配符可以使用?来表示,它可以用在类、接口、方法的参数或返回值上。它表示任何类型或未知的类型。例如,List<?>表示一个未知类型的List。它可以用来接收任何类型的List:

public void printList(List<?> list) {
    for (Object element : list) {
        System.out.print(element + " ");
    }
}

另外,通配符还可以用来限定泛型参数的上界或下界。例如,上界通配符表示参数类型必须是某个类或其子类:

public <T extends Number> void printNumber(T number) {
    System.out.println(number);
}

下界通配符则表示参数类型必须是某个类或其父类:

public void addList(List<? super Integer> list) {
    list.add(1);
    list.add(2);
}

2、类型擦除

在Java中,泛型是通过类型擦除来实现的,即在编译后,泛型信息会被擦除,变成原始类型。例如,List<String>在运行时会被当作List处理。这也是Java泛型实现中的一种取舍。它在运行时提高了性能,但在某些情况下会带来一些限制。

3、泛型与继承

在Java中,泛型类可以继承和被继承。例如:

public class Box<T> {
    private T t;
    public void set(T t) {
        this.t = t;
    }
    public T get() {
        return t;
    }
}

public class Box2<T> extends Box<T> {
    public void printValue() {
        System.out.println(get());
    }
}

Box2<String> box2 = new Box2<>();
box2.set("Hello");
box2.printValue();

另外,使用泛型时也可以通过extends和super关键字来辅助实现类型安全。例如,使用extends关键字来限制类型参数的上限:

public <T extends Comparable<T>> T max(T a, T b) {
    if (a.compareTo(b) > 0) {
        return a;
    } else {
        return b;
    }
}

4、泛型与数组

在Java中,创建泛型数组是不合法的,例如:

List<String>[] listArray = new List<String>[10]; // 编译错误

这是因为Java泛型实现中的类型擦除导致数组在运行时无法确定其元素的类型。因此,如果需要使用泛型数组,可以使用通配符或转型来实现。

四、总结

本文从基础概念、泛型类、泛型方法、通配符、类型擦除、泛型与继承、泛型与数组等方面进行了详细阐述。通过学习本文,读者可以了解Java泛型的基本原理和使用方法,掌握在编写Java代码时如何使用泛型来提高代码的类型安全和灵活性。