java-泛型

泛型:

泛型是Java 5引入的特性,用来提供类型安全,避免强制类型转换,比如集合框架里的List、Set、Map这些都用到了泛型。比如ArrayList<String>这样,确保只能添加字符串,取出来的时候也不用强转

核心概念

  • 类型参数化
    泛型允许在类、接口、方法中使用类型参数(如 <T>),使用时再指定具体类型:
List<String> list = new ArrayList<>(); // 指定存储String类型
  • 类型安全
    编译器在编译时检查类型,避免运行时类型转换错误(如 ClassCastException)。
  • 类型擦除
    Java 泛型在编译后会擦除类型信息(替换为 Object 或上界类型),运行时无法获取泛型的具体类型。

优点:

  • 泛型在编译时就能检查类型,减少运行时错误

日常应用场景:

  • 集合框架(Collections)
    泛型最典型的应用是集合类,确保集合中元素的类型一致:
List<Integer> numbers = new ArrayList<>(); // 只能添加Integer
Map<String, Integer> map = new HashMap<>(); // Key为String,Value为Integer
  • 自定义泛型类/接口
    定义可复用的通用组件,例如数据库操作的 Dao:
public interface Dao<T> {
    void save(T entity);
    T findById(Long id);
}
  • 泛型方法
    方法可以独立定义类型参数,增强灵活性:
public static <T> T getFirstElement(List<T> list) {
    return list.get(0);
}
  • 工具类与通用逻辑
    例如合并两个数组的工具方法:
public static <T> T[] mergeArrays(T[] arr1, T[] arr2) {
    T[] merged = Arrays.copyOf(arr1, arr1.length + arr2.length);
    System.arraycopy(arr2, 0, merged, arr1.length, arr2.length);
    return merged;
}
  • 通配符与边界(Wildcards)
    • 上界通配符 <? extends T>
      允许读取元素(生产者):
    void printNumbers(List<? extends Number> list) {
    for (Number n : list) System.out.println(n);
    }
    
  • 下界通配符 <? super T>
    允许写入元素(消费者):
    void addNumbers(List<? super Integer> list) {
    list.add(1);
    list.add(2);
    }	
    
  1. API 响应包装
    统一 REST API 响应格式,支持不同类型的数据:
public class Result<T> {
    private int code;
    private String message;
    private T data;
    // 构造方法、Getter/Setter
}

Result<User> userResult = new Result<>(200, "OK", user);
Result<List<Product>> productResult = new Result<>(200, "OK", products);

高级特性:

  • 类型擦除与补偿
    • 泛型信息在编译后被擦除,但可以通过以下方式绕过限制:
    public class MyClass<T> {
    private Class<T> type;
    
    public MyClass(Class<T> type) {
        this.type = type;
    }
    
    public T createInstance() throws Exception {
        return type.getDeclaredConstructor().newInstance();
    }
    }
    
  • 泛型与继承
    List 不是 List 的子类,但可以通过通配符处理:
    void processList(List<?> list) { /* 可接受任意类型 */ }
    

注意事项和限制:

  • 无法实例化泛型类型
    T obj = new T(); // 编译错误
    
  • 不能使用基本类型
    泛型参数必须是引用类型(如 Integer 而非 int)。
  • 数组与泛型
    不能直接创建泛型数组(如 new T[]),可通过反射或 ArrayList 替代。
  • 类型擦除的影响
    运行时无法通过 instanceof 检查泛型类型。

总结

  • 泛型的核心价值:
    • 类型安全:减少运行时错误。
    • 代码复用:编写更通用的逻辑。
    • 代码可读性:明确参数和返回值的类型。
### Java练习题及解析 #### 1. 类的基本使用 考虑以下类的定义: ```java class Holder<T> { T value; public Holder(T value) { this.value = value; } public T getValue() { return value; } } ``` 该类定义了一个类 `Holder`,其中 `T` 是一个类参数。可以使用该类来存储任何类的对象,并通过 `getValue()` 方法获取该对象。例如,以下代码演示了如何创建一个 `Holder` 实例来存储一个字符串: ```java Holder<String> stringHolder = new Holder<>("Hello"); System.out.println(stringHolder.getValue()); // 输出 "Hello" ``` 如果尝试将错误类的对象传递给 `Holder`,编译器会报错。例如,以下代码会导致编译错误: ```java Holder<Integer> intHolder = new Holder<>("Hello"); // 编译错误 ``` 这是因为 `Holder<Integer>` 要求传入的值必须是 `Integer` 类,而 `"Hello"` 是 `String` 类。 #### 2. 原始类的兼容性 Java 允许将类的实例赋值给原始类的变量,但这种做法不推荐,因为它会失去类安全性。例如: ```java Holder rawHolder = new Holder<String>("Hello"); String value = rawHolder.getValue(); // 不推荐,但可以编译通过 ``` 尽管这段代码可以编译通过,但它失去了带来的类检查。如果尝试从 `rawHolder` 获取一个非 `String` 类的对象,可能会在运行时抛出 `ClassCastException`。 #### 3. 类推断的增强 在 Java 23 中,类推断得到了增强,允许在某些情况下省略显式的类参数。例如: ```java List<String> list = Collections.emptyList(); // Java 23 支持空目标类推断 ``` 在旧版本的 Java 中,必须显式指定类参数: ```java List<String> list = Collections.<String>emptyList(); ``` 这种改进使得代码更加简洁,并减少了冗余的类声明。 #### 4. 可变参数与的结合 Java 允许将可变参数与结合使用。例如,可以定义一个方法来接受可变数量的参数: ```java public static <T> void printValues(T... values) { for (T value : values) { System.out.println(value); } } ``` 调用该方法时,可以传入任意数量的参数: ```java printValues("Apple", "Banana", "Cherry"); // 输出三个字符串 printValues(1, 2, 3); // 输出三个整数 ``` 这种方法在处理不确定数量的输入时非常有用,并且保持了类安全性。 #### 5. 方法的使用 不仅可以用于类,还可以用于方法。例如,定义一个方法来交换两个元素的位置: ```java public static <T> void swap(T[] array, int i, int j) { T temp = array[i]; array[i] = array[j]; array[j] = temp; } ``` 调用该方法时,可以传入任意类的数组和索引: ```java String[] names = {"Alice", "Bob"}; swap(names, 0, 1); System.out.println(Arrays.toString(names)); // 输出 "[Bob, Alice]" ``` 这种方法可以应用于任何类的数组,并且保证了类安全性。 #### 6. 接口的实现 Java 允许定义接口,并由具体的类实现这些接口。例如,定义一个接口 `Container<T>`: ```java interface Container<T> { void add(T item); T get(int index); } ``` 然后,可以实现该接口的具体类: ```java class StringContainer implements Container<String> { private List<String> items = new ArrayList<>(); @Override public void add(String item) { items.add(item); } @Override public String get(int index) { return items.get(index); } } ``` 这样,`StringContainer` 类只能用于处理 `String` 类的对象,确保了类安全性。 #### 7. 的边界限制 Java 支持通过边界限制来约束类参数的范围。例如,定义一个方法,要求类参数必须是 `Number` 的子类: ```java public static <T extends Number> double sum(T[] numbers) { double total = 0; for (T number : numbers) { total += number.doubleValue(); } return total; } ``` 调用该方法时,只能传入 `Number` 的子类数组: ```java Integer[] integers = {1, 2, 3}; Double[] doubles = {1.5, 2.5, 3.5}; System.out.println(sum(integers)); // 输出 6.0 System.out.println(sum(doubles)); // 输出 7.5 ``` 这种方法确保了类的安全性和操作的正确性。 #### 8. 多类参数的使用 Java 支持多个类参数的定义。例如,定义一个类 `Pair<K, V>`,用于存储键值对: ```java class Pair<K, V> { K key; V value; public Pair(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public V getValue() { return value; } } ``` 调用该类时,可以传入任意类的键和值: ```java Pair<String, Integer> pair = new Pair<>("Age", 25); System.out.println(pair.getKey()); // 输出 "Age" System.out.println(pair.getValue()); // 输出 25 ``` 这种方法可以灵活地处理不同类的数据组合。 #### 9. 的通配符使用 Java 支持使用通配符 `?` 来表示未知类。例如,定义一个方法来打印任意类的列表: ```java public static void printList(List<?> list) { for (Object obj : list) { System.out.println(obj); } } ``` 调用该方法时,可以传入任意类的 `List`: ```java List<String> stringList = Arrays.asList("A", "B", "C"); List<Integer> integerList = Arrays.asList(1, 2, 3); printList(stringList); // 输出三个字符串 printList(integerList); // 输出三个整数 ``` 这种方法在处理未知类的数据时非常有用,并且保持了类安全性。 #### 10. 的递归类限制 Java 支持递归类限制,允许类参数继承自身。例如,定义一个接口 `SelfBound<T>`: ```java interface SelfBound<T extends SelfBound<T>> { T self(); } ``` 这种设计模式常用于链式调用和构建器模式中,确保返回的类与当前类一致。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

在下陈平安

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值