Java泛型:从基础到高级应用
立即解锁
发布时间: 2025-08-17 02:35:38 阅读量: 17 订阅数: 22 


Java编程基础与SCJP认证指南
### Java泛型:从基础到高级应用
#### 1. 泛型基础与子类型
在Java编程中,泛型是一项强大的特性,它允许我们创建可重用的代码组件,同时提高代码的类型安全性。例如,有如下代码:
```java
class IntegerBiNode extends BiNode<Integer> {
// A non-generic subtype
IntegerBiNode(Integer data, IntegerBiNode next, IntegerBiNode previous) {
super(data, next, previous);
}
//...
}
```
这里的`IntegerBiNode`是`BiNode<Integer>`的一个非泛型子类型。需要注意的是,一个子类型只能继承同一个泛型接口超类型的一种参数化形式。例如下面的代码会产生错误:
```java
class WeirdNode<E> extends MonoNode<E> implements IMonoLink<Integer> { // Error!
//...
}
```
在扩展引用类型时具有很大的灵活性,但要实现预期的结果,必须谨慎操作。
#### 2. 原始类型与未检查警告
没有形式类型参数的泛型类型称为原始类型。原始类型是泛型类所有参数化类型的超类型。例如,原始类型`Node`是参数化类型`Node<String>`、`Node<Integer>`和`Node<Node<String>>`的超类型。参数化类型(如`Node<String>`)不是类,编译器使用参数化类型来检查程序中创建的对象是否被正确使用。所有参数化类型在运行时都由其原始类型表示,即编译器不会为每个参数化类型创建一个新类。
只有引用类型(不包括数组创建和枚举)可以用于泛型类型的调用,原始类型不能作为实际类型参数,因为原始类型的值大小不同,而Java中泛型类只有一种实现。
泛型仅在编译器中实现,JVM对泛型类型的使用并不了解,它不会区分`Node<String>`和`Node<Integer>`,只知道类`Node`。编译器通过类型擦除过程翻译泛型类,即擦除类型参数的信息并插入强制类型转换,以确保程序在运行时类型安全。
可以仅使用原始类型来使用泛型类,就像使用非泛型类一样,而不指定其实际类型参数。但编译器会在这种使用可能在运行时导致问题时发出未检查警告。这种用法是为了与旧代码保持向后兼容性,但在编写新代码时强烈不建议使用。例如以下代码:
```java
Node rawNode = intNode; // (5) Assigning to raw type always possible.
rawNode.setData("BOOM"); // (6) Unchecked call warning!
Node<Integer> intNode = rawNode; // (7) Unchecked conversion warning!
iRef = intNode.getData();
// (8) ClassCastException!
```
将原始类型的引用值赋给参数化类型的引用会导致未检查转换警告。如果原始类型引用的节点不是`Integer`类型,将其用作`Integer`节点可能会在运行时导致问题。
以下是一个完整的示例代码,展示了未检查警告的情况:
```java
//A client for the generic class Node<T>.
public class Preliminaries {
public static void main(String[] args) {
Node<Integer> intNode = new Node<Integer>(2008, null);
Integer iRef = intNode.getData();
// 2008
intNode.setData(2010);
// Ok.
// intNode.setData("TwentyTen");
// (1) Compile-time error!
intNode.setNext(new Node<Integer>(2009, null)); // (2010, (2009, null))
// intNode.setNext(new Node<String>("Hi", null)); // (2) Compile-time error!
Node<String> strNode = new Node<String>("hi", null);
// intNode = strNode;
// (3) Compile-time error!
String str = strNode.getData(); // (4) No explicit cast necessary.
Node rawNode = intNode; // (5) Assigning to raw type always possible.
rawNode.setData("BOOM"); // (6) Unchecked call warning!
intNode = rawNode;
// (7) Unchecked conversion warning!
iRef = intNode.getData();
// (8) ClassCastException!
}
}
```
编译该程序时会出现以下警告:
```plaintext
>javac -Xlint:unchecked Preliminaries.java
Preliminaries.java:16: warning: [unchecked] unchecked call to setData(E) as a
member of the raw type Node
rawNode.setData("BOOM"); // (6) Unchecked call warning!
^
Preliminaries.java:17: warning: [unchecked] unchecked conversion
found : Node
required: Node<java.lang.Integer>
intNode = rawNode;
// (7) Unchecked conversion warning!
^
2 warnings
```
运行该程序会抛出`ClassCastException`异常:
```plaintext
>java Preliminaries
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot
be cast to java.lang.Integer
at Preliminaries.main(Preliminaries.java:18)
```
#### 3. 集合与泛型
在Java 1.5引入泛型之前,Java集合框架中的集合可以持有任何类型对象的引用。例如:
```java
List wordList = new ArrayList(); // Using non-generic types.
wordList.add("two zero zero eight"); // Can add any object.
wordList.add(2004);
//...
Object element = wordList.get(0); // Always returns an Object.
//...
if (element instanceof String) { // Runtime check to avoid ClassCastException
String strInt = (String) element; // Cast required.
//...
}
```
集合的客户端必须做大部分的记录工作,以确保以类型安全的方式使用集合。使用`Object`类作为元素类型允许集合类的实现是具体的,但使用是通用的。
使用泛型集合时,编译器提供类型安全,并且生成的代码更简洁:
```java
List<String> wordList = new ArrayList<String>(); // Using a specific type.
wordList.add("two zero zero eight");
// Can add strings only
wordList.add(2004);
// Compile-time error!
//...
String element = wordList.get(0);
// Always returns a String.
//...
```
此时不需要运行时检查或显
0
0
复制全文
相关推荐









