【问题标题】:Java Casting Abstract Between Two Concrete ClassesJava 在两个具体类之间转换抽象
【发布时间】:2018-03-14 15:52:09
【问题描述】:

我正在实现一个工厂模式,以在抽象中创建两个具体类,其中工厂方法重载(见下文):

public abstract class User {
    ...
    public static User make(int id, String name) {
        return new Admin(id, name); 
    }

    public static User make(int id, int student_id, String name) {
        return new Student(id, student_id, name); 
    }
}

这是工厂调用:

ArrayList<User> users = new ArrayList<>(
    Arrays.asList(
        User.make(1000, "Andy"),    // makes new Admin
        User.make(1001, 101001, "Bob")    // makes new Student
    )
);

这里是 Admin 类:

public class Admin extends User {
    ...
    // constructor
    protected Admin(int id, String name) {
        super(id, name);
    }
    ...
}

这里是学生类:

public class Student extends User {
    ...
    // constructor
    protected Student(int id, int student_id, String name) {
        super(id, name);
        this.student_id = student_id;
    }
    ...
}

这些具体的每一个都被放置在一个用户数组列表中。我有一个函数(如下),它遍历列表并进行运行时推断以调用每个具体的特定方法;但是,我在 IDE 中收到 ClassCastException 错误,指出无法将 Admin 转换为 Student。

完整的异常消息是: 线程“main”java.lang.ClassCastException 中的异常:presentation_layer.Admin 无法转换为presentation_layer.Student

public class App {
    ...
    public static void main(String[] args) {
        ArrayList<User> users = new ArrayList<>(
            Arrays.asList(
                User.make(1000, "Andy"),        // makes new Admin
                User.make(1001, 101001, "Bob")  // makes new Student
            )
        );

        users.forEach((u) -> {
            if (u instanceof Admin)) {
                System.out.println("hello admin");
                ((Admin)u).anAdminFunc();
            } else if (u instanceof Student)) {
                System.out.println("hello student");
                ((Student)u).aStudentFunc();
            }
        });
    }
    ...
}

当我注释掉具体的方法调用时,相应的打印语句按预期输出,没有错误;但是,当尝试在每次循环迭代之间使用这些独特的方法调用时,我得到了转换错误。您能否告诉我如何解决这个问题以及我做错了什么,无论是我的推理方法还是我的工厂模式方法?

【问题讨论】:

  • 发布一个完整的最小示例来重现问题,以及异常的完整和准确的堆栈跟踪。
  • 你能在导致类转换异常的行之前打印d.getClass().getName()的结果吗?另外,当您更改为d instanceof Admin 时会发生什么?会不会是 Admin 是与导入的包不同的包中的一个类?
  • @ErnestKiwele 我添加了完整的异常消息。我正在尝试现在的实例。
  • 您的代码在另一个方法声明中包含一个方法声明。它不可能编译。发布一个完整的最小示例来重现该问题。我们必须能够复制它,将其粘贴到我们的 IDE 中,编译并运行它。已经多次要求您这样做,但您不会这样做。所以投票结束。
  • @Jim22150 动态绑定是 Java 的标准功能,设计和创建多态对象是 100% 可以的。我唯一要改变的是需要在运行时检查类名。如果您按合同进行设计,那么User 上的方法应该适用于具体类型并在需要时被覆盖。因此,对用户列表的元素调用用户方法更为明智,即使每个元素的具体类型都可以覆盖或实现这些方法。

标签: java casting type-inference


【解决方案1】:

使用 instanceof 代替。 另外,如果你发现自己做了很多转换,你可能需要重新考虑你对继承的使用

【讨论】:

  • 我也试过了,好像遇到了同样的异常错误
  • instanceof 不能失败。其他事情正在发生。你的类是什么样的(在继承方面)?
  • 我添加了一些额外的代码,希望能提供更多的上下文
  • instanceof 帮助我简化了我的代码,并且包含它似乎在进一步重构时解决了我最初的问题。谢谢@pecks!
【解决方案2】:

试试这个:

    public static User make(int id, String name) {
      User user = new Admin(id,name);
      return user; 
}

public static User make(int id, int student_id, String name) {
     User user = new Student(id, student_id, name);
     return user; 
}

参考:parent-child type conversion

【讨论】:

  • 这实际上与他现在拥有的没有什么不同!
  • 显然这是来自另一个主题的评论:Once you create an object, you can't change its type.
  • 检查答案@pecks中的链接
  • @Arun 我正在使用 Java 9 .. 我看不到额外语法的影响。谢谢,但它一定是别的东西。我正在努力扩展我的问题以尽快添加更多代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-17
  • 1970-01-01
  • 2012-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-26
相关资源
最近更新 更多