java - ClassCastException 即使在使用泛型之后
问题描述
在泛型之前
List list = new ArrayList<>();
list.add(new Manager(2));
for(Object obj : list){
System.out.println(((Clerk)obj).display1());
}
// will lead to class cast exception.
泛型是为了避免强制转换而派生的。我编写了一些代码,即使在使用泛型之后也会给出 ClassCastException。
class Employee{
int age;
Employee(int age){
this.age = age;
}
public void display(){
System.out.println("age:"+age);
}
}
class Manager extends Employee{
int age;
Manager(final int age) {
super(55);
this.age = age;
}
public void display(){
System.out.println("age:"+age);
}
}
class Clerk extends Employee{
int age;
Clerk(final int age) {
super(55);
this.age = age;
}
public void display1(){
System.out.println("age:"+age);
}
}
public static void main(String[] args) {
List<Manager> list1 = new ArrayList<>();
list1.add(new Manager(22));
test(list1);
}
private static void test(List<? extends Employee> list){
for(Employee employee1 : list){
((Clerk)employee1).display1();
}
}
在该方法test
中,我使用了下界泛型参数。我已经通过了作为员工子类的经理列表,但是在test
我已经为另一个员工子类提供了实现,类文员导致类转换异常。
Exception in thread "main" java.lang.ClassCastException: class generics.Manager cannot be cast to class generics.Clerk (generics.Manager and generics.Clerk are in unnamed module of loader 'app')
at generics.GenericsDemo.test(GenericsDemo.java:56)
at generics.GenericsDemo.main(GenericsDemo.java:50)
我能够编译和执行代码意味着 Java 支持此功能,我可以在生产中使用它。如果我无法访问任何调用方方法,没有任何类,并且我需要提供测试方法的实现,那么我应该如何处理这个异常?
我应该instanceof
在类型转换之前使用吗?我想从技术上了解如何处理,而不是从根本上理解它是正确还是不正确,只是如何处理异常。
解决方案
您的代码从根本上是错误的。
您创建了一个 Manager,然后期望将其视为 Clerk。
经理不是文员,这就是它的结束。
即使列表是员工列表,一旦您创建了经理,它就是经理,当它在员工列表中时,它仍然是经理。您不能只是决定要让经理成为文员。
您的类层次结构中可能的强制转换:
经理对员工(通常是隐含的)
职员到员工(通常是隐含的)
Employee 到 Manager(当且仅当对象实际上是 Manager 时)
Employee to Clerk(当且仅当对象实际上是 Clerk 时)
要更具体地说明错误在哪里,就是这种方法:
private static void test(List<? extends Employee> list){
for(Employee employee1 : list){
((Clerk)employee1).display1();
}
}
方法声明说它可以处理员工列表或从员工继承的对象。
该方法已实现,因此如果列表包含任何实际上不是 Clerk 的 Employee,它将引发异常。
假设抛出这样的异常实际上不是“测试”方法的意图,那么实现和声明需要兼容。为什么方法没有定义为
private static void test(List<Clerk> list)
因为这就是它可以处理的全部内容,因此定义它允许在编译时验证类型。
或者,只需将他们视为员工。可以显示任何员工。
private static void test(List<? extends Employee> list){
for (Employee employee : list) {
employee.display();
}
}
推荐阅读
- python - 将 TensorFlow 模型转换为 TFLITE 格式
- python - 当列表中的红色后跟绿色时,为什么我的 for 循环不改变颜色?
- bluesnap - 创建订单状态码 400 - 服务器错误
- python - Python tkinter 范围标签不显示
- c++ - 函数中的 C++ 和号
- c++ - std::string 类继承和繁琐的 c++ 重载解析 #2
- hibernate - Hibernate 与聚合的关系
- python-3.x - Python3,子进程,总是得到非类型错误
- c++ - 为什么我的窗口没有显示任何 QPixmap 图片?
- r-markdown - 如何在 Xaringan 幻灯片中嵌入视频 (avi/mpg4)