【入门基础】java泛型和通配符详解
文章目录
- 前言
- 泛型类
- 泛型方法
- 泛型接口
- 通配符(Wildcards)
- 使用场景
- 非主流用法
- 总结
前言
Java泛型(Generics)是JDK 5中引入的一个新特性,它提供了编译时类型安全检测机制,允许程序员在编译时检测到非法的类型。泛型的主要目的是在编译期间对类型进行检查,使得类型错误能在编译时而不是运行时被捕获,从而提高程序的稳定性和安全性。同时,它也消除了类型转换的代码,使得代码更加简洁和易于维护。
泛型类
泛型类是在类定义时,类名后面加上一对尖括号<>,尖括号中放置类型参数(type parameters)。例如:
java
复制代码
public class Box<T> { private T t; public void set(T t) { this.t = t; } public T get() { return t; }
}
这里的T就是一个类型参数,它指定了Box类内部将使用哪种类型的数据。在创建Box类的实例时,可以指定具体的类型,例如Box。
泛型方法
泛型方法不仅能在类级别定义类型参数,还能在方法级别定义。泛型方法允许在调用方法时指定类型参数。例如:
java
复制代码
public class Util { public static <T> T getFirst(T[] inputArray) { if (inputArray.length == 0) { throw new IllegalArgumentException("Array is empty"); } return inputArray[0]; }
}
这里定义了一个类型参数T,它表示该方法将返回一个与数组类型相同的对象。
泛型接口
泛型接口与泛型类类似,接口名后面也可以定义类型参数。例如:
java
复制代码
public interface Pair<K, V> { public K getKey(); public V getValue();
}
这里<K, V>定义了两个类型参数K和V,分别代表键值对的键和值的类型。
通配符(Wildcards)
通配符?用于泛型中,表示未知的类型。它主要有三种用法:
- 无界通配符(Unbounded Wildcards):使用?表示未知的类型,例如List<?>可以表示任何类型的List。
- 上界通配符(Upper Bounded Wildcards):使用? extends T表示未知的类型,但它是T或T的子类。例如List<? extends Number>可以表示List或List等。
- 下界通配符(Lower Bounded Wildcards):使用? super T表示未知的类型,但它是T或T的父类。例如List<? super Integer>可以表示List或List等。
使用场景
- 无界通配符:常用于需要读取但不需要写入集合的场景,因为它保证了类型安全但限制了向集合添加元素。
- 上界通配符:常用于需要从集合中读取元素的场景,并且你知道这些元素至少是某个类型的实例。
- 下界通配符:常用于需要向集合中添加元素的场景,并且你添加的元素类型是这个集合中元素类型的父类型。
非主流用法
- 泛型数组:虽然在Java中不能直接创建泛型数组(如T[] array = new T[10];是编译错误的),但可以通过反射(Array.newInstance)或泛型方法的类型参数来间接创建泛型数组。这种用法不常见,因为需要处理额外的复杂性和性能开销。
- 泛型枚举:Java允许在枚举中使用泛型。虽然枚举通常用于表示一组固定的常量,但泛型枚举可以提供额外的灵活性,例如允许枚举值持有不同类型的对象。这种用法较为特殊,但在需要枚举与类型关联时非常有用。
- 泛型异常:Java泛型不能用于throws子句中声明的异常类型,因为异常处理是在运行时进行的,而泛型信息在编译时就被擦除了。然而,可以通过泛型方法或泛型类来封装异常处理逻辑,以提供类型安全的异常处理。这种用法虽然不是直接对异常类型使用泛型,但实现了类似的效果。
- 混合使用上下界通配符:
虽然在实际编程中不常见,但可以混合使用上界(? extends T)和下界(? super T)通配符来创建复杂的类型约束。这种用法通常用于需要同时满足读取和写入操作,且对类型有严格要求的场景。然而,由于这种用法较为复杂且易出错,因此不是主流用法。 - 在泛型类/接口声明中使用通配符:
虽然在类/接口声明中直接使用通配符(如class MyClass<? extends T> {…})是不合法的,但可以在类/接口内部的方法或字段中使用通配符来提供额外的灵活性。这种用法虽然不常见,但在设计复杂的泛型API时可能会用到。 - 利用通配符实现多态性:
通配符提供了一种在泛型代码中实现多态性的方式。虽然这不是通配符独有的特性(泛型本身就是为了提供类型安全的多态性),但通配符的灵活性使得在某些情况下可以更加优雅地实现多态性。例如,使用List<?>作为方法参数可以接受任何类型的List,从而提供更大的灵活性。
总结
需要注意的是,上述非主流用法并非推荐的做法,它们可能增加代码的复杂性和出错的风险。在大多数情况下,应优先考虑使用泛型和通配符的主流用法来编写清晰、简洁、易于维护的代码。同时,随着Java语言的发展和新特性的引入,一些曾经看似非主流的用法可能会逐渐变得主流或过时。因此,建议始终关注Java语言的最新动态和最佳实践。
我是杰叔叔,一名沪漂的码农,下期再会!