怎么使用Java泛型

发布时间:2021-07-05 16:39:59 作者:chen
来源:亿速云 阅读:222
# 怎么使用Java泛型

## 一、泛型概述

### 1.1 什么是泛型
泛型(Generics)是Java SE 5.0引入的重要特性,它允许在定义类、接口和方法时使用类型参数(type parameters)。这种参数化类型的能力让代码可以应用于多种数据类型,同时保持编译时的类型安全。

```java
// 没有泛型的例子
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0); // 需要强制类型转换

// 使用泛型的例子
List<String> list = new ArrayList<>();
list.add("hello");
String s = list.get(0); // 自动类型推断

1.2 为什么需要泛型

二、泛型基础语法

2.1 泛型类

在类名后面添加类型参数声明,可以有一个或多个类型参数。

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

// 使用示例
Box<Integer> integerBox = new Box<>();
integerBox.set(10);
Integer value = integerBox.get();

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;
    
    // 实现方法...
}

2.3 泛型方法

在方法返回类型前声明类型参数,可以用于静态和非静态方法。

public class Util {
    public static <T> T getMiddle(T... a) {
        return a[a.length / 2];
    }
}

// 使用示例
String middle = Util.<String>getMiddle("John", "Q.", "Public");
// 类型推断
Number middleNum = Util.getMiddle(3.14, 1729, 0);

三、类型参数命名约定

按照Java惯例,类型参数名称使用单个大写字母: - E - Element(集合元素) - K - Key(键) - V - Value(值) - T - Type(类型) - S,U,V - 第二、第三、第四类型

四、泛型的高级特性

4.1 类型通配符

使用问号(?)表示未知类型,常用于方法参数。

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

4.2 有限制的通配符

可以限制通配符的上界或下界。

上界通配符<? extends T> 表示T或其子类

public static double sumOfList(List<? extends Number> list) {
    double sum = 0.0;
    for (Number num : list) {
        sum += num.doubleValue();
    }
    return sum;
}

下界通配符<? super T> 表示T或其父类

public static void addNumbers(List<? super Integer> list) {
    for (int i = 1; i <= 10; i++) {
        list.add(i);
    }
}

4.3 泛型擦除

Java泛型是通过类型擦除实现的,编译器在编译时去掉类型参数信息。

// 编译前
List<String> list = new ArrayList<>();
list.add("hello");
String s = list.get(0);

// 编译后(近似)
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);

五、泛型使用限制

5.1 不能实例化类型参数

public static <E> void append(List<E> list) {
    E elem = new E();  // 编译错误
    list.add(elem);
}

5.2 不能创建泛型数组

List<Integer>[] arrayOfLists = new List<Integer>[2];  // 编译错误

5.3 静态上下文限制

静态字段或方法不能引用类的类型参数。

public class MobileDevice<T> {
    private static T os;  // 编译错误
    
    public static T getOS() {  // 编译错误
        return os;
    }
}

5.4 不能抛出或捕获泛型类实例

// 编译错误
try {
    // ...
} catch (SomeException<Integer> e) {
    // ...
}

六、泛型最佳实践

6.1 PECS原则

Producer-Extends, Consumer-Super(生产者使用extends,消费者使用super)

// 正确示例
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
    for (int i = 0; i < src.size(); i++) {
        dest.set(i, src.get(i));
    }
}

6.2 优先使用泛型方法

当方法操作独立于类类型参数时,使用泛型方法更灵活。

// 优于在类上定义类型参数
public static <T> List<T> filter(List<T> list, Predicate<T> p) {
    List<T> result = new ArrayList<>();
    for (T t : list) {
        if (p.test(t)) {
            result.add(t);
        }
    }
    return result;
}

6.3 避免原生类型

总是使用泛型类型,避免使用原生类型(raw type)。

List list = new ArrayList();  // 避免
List<String> list = new ArrayList<>();  // 推荐

七、实际应用示例

7.1 泛型缓存系统

public class Cache<K, V> {
    private Map<K, V> cacheMap = new HashMap<>();
    
    public void put(K key, V value) {
        cacheMap.put(key, value);
    }
    
    public V get(K key) {
        return cacheMap.get(key);
    }
    
    public void remove(K key) {
        cacheMap.remove(key);
    }
}

7.2 通用比较工具

public class CompareUtil {
    public static <T extends Comparable<T>> T max(T a, T b) {
        return a.compareTo(b) > 0 ? a : b;
    }
    
    public static <T extends Comparable<? super T>> void sort(List<T> list) {
        Collections.sort(list);
    }
}

八、常见问题解答

8.1 泛型能否用于基本类型?

不能直接使用,必须使用对应的包装类。Java的泛型是基于对象的,基本类型不是对象。

8.2 如何检查泛型类型?

由于类型擦除,运行时无法直接检查泛型类型。可以通过传递Class对象来解决:

public <T> void checkType(Object obj, Class<T> type) {
    if (type.isInstance(obj)) {
        T t = type.cast(obj);
        // 处理t
    }
}

8.3 泛型与多态如何配合?

子类可以继承或扩展父类的泛型参数:

class Parent<T> {}
class Child<T> extends Parent<T> {}
class StringChild extends Parent<String> {}

九、总结

Java泛型是强大的语言特性,正确使用可以: 1. 提高代码的类型安全性 2. 减少类型转换的繁琐 3. 增强代码的可读性和重用性 4. 使API设计更加灵活

虽然泛型有一些限制(主要是由于类型擦除),但通过合理的设计模式和使用技巧,可以充分发挥其优势。掌握泛型是成为高级Java开发者的必备技能。


本文涵盖了Java泛型的主要知识点,从基础概念到高级应用,共约3700字。通过示例代码和最佳实践,帮助读者全面理解并正确使用Java泛型。在实际开发中,应根据具体场景灵活运用泛型特性,编写出更安全、更灵活的代码。 “`

推荐阅读:
  1. 如何理解java泛型
  2. 如何使用Java泛型

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:Python中怎么实现增量备份

下一篇:Python中如何操作文件路径

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》