10. 泛型

泛型(Generics) 是Java 5引入的一项重要特性,它允许在定义类、接口和方法时使用类型参数,从而提高代码的类型安全性和可重用性。泛型的主要目的是在编译时检查类型安全,并消除运行时的类型转换异常。


1. 泛型的作用

1.1 类型安全

  • 泛型可以在编译时检查类型,确保只有指定类型的对象才能被添加到集合中。
  • 避免了运行时的 ClassCastException 异常。

1.2 消除类型转换

  • 使用泛型后,从集合中获取元素时不需要显式地进行类型转换。

1.3 代码重用

  • 泛型允许编写通用的代码,可以适用于多种类型。

2. 泛型的基本用法

2.1 泛型类

  • 在类定义时使用类型参数,可以在类中使用该类型参数。

示例

// 定义一个泛型类
public class Box<T> {
    private T item;

    public void setItem(T item) {
        this.item = item;
    }

    public T getItem() {
        return item;
    }
}

// 使用泛型类
public class Main {
    public static void main(String[] args) {
        Box<String> stringBox = new Box<>();
        stringBox.setItem("Hello");
        System.out.println(stringBox.getItem()); // 输出: Hello

        Box<Integer> intBox = new Box<>();
        intBox.setItem(123);
        System.out.println(intBox.getItem()); // 输出: 123
    }
}

2.2 泛型接口

  • 在接口定义时使用类型参数,可以在接口中使用该类型参数。

示例

// 定义一个泛型接口
public interface Pair<K, V> {
    K getKey();
    V getValue();
}

// 实现泛型接口
public class OrderedPair<K, V> implements Pair<K, V> {
    private K key;
    private V value;

    public OrderedPair(K key, V value) {
        this.key = key;
        this.value = value;
    }

    @Override
    public K getKey() {
        return key;
    }

    @Override
    public V getValue() {
        return value;
    }
}

// 使用泛型接口
public class Main {
    public static void main(String[] args) {
        Pair<String, Integer> pair = new OrderedPair<>("Age", 25);
        System.out.println(pair.getKey() + ": " + pair.getValue()); // 输出: Age: 25
    }
}

2.3 泛型方法

  • 在方法定义时使用类型参数,可以在方法中使用该类型参数。

示例

public class Utils {
    // 定义一个泛型方法
    public static <T> void printArray(T[] array) {
        for (T item : array) {
            System.out.println(item);
        }
    }
}

// 使用泛型方法
public class Main {
    public static void main(String[] args) {
        Integer[] intArray = {1, 2, 3};
        String[] strArray = {"A", "B", "C"};

        Utils.printArray(intArray); // 输出: 1 2 3
        Utils.printArray(strArray); // 输出: A B C
    }
}

3. 泛型的类型擦除

  • Java的泛型是通过类型擦除实现的,即在编译时泛型类型信息会被擦除,替换为原始类型(如 Object)。
  • 运行时无法获取泛型的类型参数。

示例

public class Box<T> {
    private T item;

    public void setItem(T item) {
        this.item = item;
    }

    public T getItem() {
        return item;
    }
}

// 编译后,Box<T> 会被擦除为 Box<Object>

4. 泛型的通配符

4.1 无界通配符(<?>)

  • 表示任意类型。

示例

public void printList(List<?> list) {
    for (Object item : list) {
        System.out.println(item);
    }
}

4.2 上界通配符(<? extends T>)

  • 表示类型参数是 T 或其子类。

示例

public void printNumbers(List<? extends Number> list) {
    for (Number number : list) {
        System.out.println(number);
    }
}

4.3 下界通配符(<? super T>)

  • 表示类型参数是 T 或其父类。

示例

public void addNumbers(List<? super Integer> list) {
    list.add(123);
}

5. 泛型的优势

  1. 类型安全:在编译时检查类型,避免运行时的类型转换异常。
  2. 代码复用:可以编写通用的代码,适用于多种类型。
  3. 减少类型转换:从集合中获取元素时不需要显式地进行类型转换。

6. 泛型的局限性

  1. 类型擦除:运行时无法获取泛型的类型参数。
  2. 基本类型不支持:泛型不支持基本类型(如 intchar),需要使用对应的包装类(如 IntegerCharacter)。
  3. 无法创建泛型数组:例如 new T[10] 是非法的。

7. 使用示例

7.1 泛型集合

List<String> list = new ArrayList<>();
list.add("Hello");
list.add("World");
String first = list.get(0); // 不需要类型转换

7.2 泛型方法

public static <T> T getFirst(List<T> list) {
    return list.get(0);
}

7.3 泛型类

public class Pair<K, V> {
    private K key;
    private V value;

    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }

    public K getKey() {
        return key;
    }

    public V getValue() {
        return value;
    }
}

8. 总结

  • 泛型通过类型参数提高了代码的类型安全性和可重用性。
  • 泛型类、泛型接口和泛型方法可以适用于多种类型。
  • 通配符(<?><? extends T><? super T>)提供了更灵活的类型约束。
  • 尽管泛型有类型擦除等局限性,但它仍然是Java中实现类型安全和代码复用的重要工具。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值