Java高级语言特性深入解析
立即解锁
发布时间: 2025-08-19 00:10:18 阅读量: 14 订阅数: 36 


深入浅出Java与Android开发
### Java高级语言特性深入解析
#### 泛型方法与通配符
在Java编程中,泛型是一项强大的特性,但在使用过程中也会遇到一些类型安全相关的问题。例如,`List<String>` 并不等同于 `List<Object>`,若要调用 `outputList()` 方法而不违反类型安全,只能传递 `List<Object>` 类型的参数,这限制了方法的实用性。不过,泛型提供了通配符参数 `?` 来解决这个问题,将 `outputList()` 的参数类型从 `List<Object>` 改为 `List<?>`,就可以使用 `List<String>`、`List<Employee>` 等不同类型的列表来调用该方法。
当需要编写一个将任意类型对象的列表复制到另一个列表的方法时,若简单地编写 `void copyList(List<Object> src, List<Object> dest)` 方法,其用途会受到限制,因为它只能复制元素类型为 `Object` 的列表,无法复制 `List<Employee>` 这样的列表。若要传递元素类型任意但一致的源列表和目标列表,需要使用通配符作为类型占位符,例如:
```java
static void copyList(List<?> src, List<?> dest)
{
for (int i = 0; i < src.size(); i++)
dest.add(src.get(i));
}
```
然而,这个方法会在编译时出现错误,错误信息表明 `dest.add(src.get(i))` 方法调用违反了类型安全。因为 `?` 意味着任何类型的对象都可以作为列表的元素类型,所以目标列表的元素类型可能与源列表的元素类型不兼容。例如,将 `List<String>` 作为源列表,`List<Employee>` 作为目标列表,尝试将源列表的元素添加到目标列表中会违反类型安全,若允许这样的复制操作,在获取目标列表的元素时会抛出 `ClassCastException` 异常。
可以通过以下方式有限地解决这个问题:
```java
static void copyList(List<? extends String> src,
List<? super String> dest)
{
for (int i = 0; i < src.size(); i++)
dest.add(src.get(i));
}
```
这个方法展示了通配符参数的一个特性,即可以提供上界或下界来限制可以作为泛型类型实际类型参数传递的类型。`? extends String` 表示可以传递 `String` 或其任何子类作为实际类型参数,`? super String` 表示可以传递 `String` 或其任何超类作为实际类型参数。由于 `String` 不能有子类,所以只能传递 `String` 类型的源列表和 `String` 或 `Object` 类型的目标列表。
复制任意元素类型列表的问题可以通过泛型方法来解决。泛型方法的语法表示为 `<formal_type_parameter_list> return_type identifier(parameter_list)`,形式类型参数列表与指定泛型类型时相同,由带有可选边界的类型参数组成。类型参数可以作为方法的返回类型,也可以出现在参数列表中,编译器会从方法调用的上下文中推断实际类型参数。
可以很容易地将 `copyList()` 转换为泛型方法,在返回类型前加上 `<T>` 并将每个通配符替换为 `T`,得到的方法头为 `<T> void copyList(List<T> src, List<T> dest)`,示例代码如下:
```java
import java.util.ArrayList;
import java.util.List;
class Circle
{
private double x, y, radius;
Circle(double x, double y, double radius)
{
this.x = x;
this.y = y;
this.radius = radius;
}
@Override
public String toString()
{
return "(" + x + ", " + y + ", " + radius + ")";
}
}
public class CopyList
{
public static void main(String[] args)
{
List<String> ls = new ArrayList<String>();
ls.add("A");
ls.add("B");
ls.add("C");
outputList(ls);
List<String> lsCopy = new ArrayList<String>();
copyList(ls, lsCopy);
outputList(lsCopy);
List<Circle> lc = new ArrayList<Circle>();
lc.add(new Circle(10.0, 20.0, 30.0));
lc.add(new Circle (5.0, 4.0, 16.0));
outputList(lc);
List<Circle> lcCopy = new ArrayList<Circle>();
copyList(lc, lcCopy);
outputList(lcCopy);
}
static <T> void copyList(List<T> src, List<T> dest)
{
for (int i = 0; i < src.size(); i++)
dest.add(src.get(i));
}
static void outputList(List<?> list)
{
for (int i = 0; i < list.size(); i++)
System.out.println(list.get(i));
System.out.println();
}
}
```
泛型方法的类型参数是从方法调用的上下文中推断出来的。例如,编译器会确定 `copyList(ls, lsCopy)` 是将 `List<String>` 复制到另一个 `List<String>`,`copyList(lc, lcCopy)` 是将 `List<Circle>` 复制到另一个 `List<Circle>`。运行这个应用程序,会得到相应的输出结果。
#### 数组与泛型
在Java中,由于泛型的实现方式,不能指定涉及类型参数或实际类型参数的数组创建表达式,如 `new E[size]` 或 `new List<E>[50]`、`new Queue<String>[15]`,若尝试这样做,编译器会报告泛型数组创建错误信息。
在深入探讨为什么允许涉及类型参数或实际类型参数的数组创建表达式是危险的之前,需要理解数组上下文中的具体化、协变性以及泛型实现的核心——类型擦除。
具体化是将抽象表示为具体,Java数组是具体化的,它们知道自己的元素类型(元素类型存储在内部),并可以在运行时强制执行这些类型。尝试在数组中存储无效元素会导致虚拟机抛出 `java.lang.ArrayStoreException` 类的实例。例如:
```java
class Point
{
int x, y;
}
class ColoredPoint extends Point
{
int color;
}
public class ReificationDemo
{
public static void main(String[] args)
{
ColoredPoint[] cptArray = new ColoredPoint[1];
Point[] ptArray = cptArray;
ptArray[0] = new Point();
}
}
```
在这个例子中,`ColoredPoint[] cptArray = new ColoredPoint[1];` 是合法的,但 `ColoredPoint[] cptArra
0
0
复制全文
相关推荐










