【问题标题】:Cast an object to class type passed as parameter将对象转换为作为参数传递的类类型
【发布时间】:2015-11-06 11:02:41
【问题描述】:

我有一个父类和 2 个子类。我正在尝试实现一个函数,该函数将孩子的类型和哪个孩子作为参数。

当我使用child.newInstance() 时,我想将其存储在传递的类型的变量中,并从第二个参数调用函数。

以下是类

public class Parent {
    public void test() {
        System.out.println("Test from parent");
    }
}

public class ChildA extends Parent {
    public void testChildA() {
        System.out.println("Test from child a");
    }
}

public class ChildB extends Parent {
    public void testChildB() {
        System.out.println("Test from child b");
    }
}

这是我正在尝试实现的方法

public class Driver {
    Parent func(Class child, String whichChild) throws Exception {
        // whichChild: "ChildA" or "ChildB"

        Object obj = child.newInstance();
        // cast obj to type of child and call the method "test" and "test" + whichChild
    }
}

可以完成我想做的事情吗?如果是,如何将此对象转换为传递的类型?

【问题讨论】:

  • 你想用这个实现什么?为什么不直接覆盖孩子的测试?
  • 我不能改变类的结构也不能覆盖方法,因为子方法有其他功能,我错误地添加了super.test();,对此感到抱歉
  • 编译时安全和静态分析是非常强大和有用的工具,当使用反射 API 时,您会失去它们提供的所有好处。在运行之前,您不会知道代码是否有效。无法找到您通过反射调用的方法的用法。 IDE 还会报告未使用的方法,这是不正确的。请参阅 Andy Turner 的回答,这样做的最佳方法是什么。
  • @aizen92 你能在Parent 类中添加额外的抽象方法吗?
  • @aizen92 这听起来像是继承的完美场所。为什么不能修改Parent类?

标签: java class generics


【解决方案1】:

不确定你在做什么,但你可以使用Class.cast(...)

例如

public <T> T getInstance(Class<T> type) {
    Object o = type.newInstance();
    T t = type.cast(o);
    return t;
}

【讨论】:

  • return type.newInstance() 会更简单。
  • 同意,我只是想展示Class.cast(Object)的用法
【解决方案2】:

如果您向child 添加约束,则根本不需要强制转换即可获得 Parent:

Parent func(Class<? extends Parent> child, String whichChild) throws Exception {
    // whichChild: "ChildA" or "ChildB"

    Parent obj = child.newInstance();
    //...
}

但是,您仍然不能调用testChildA 等方法,因为您所拥有的只是Parent 的一个实例。您需要使用反射来获取方法:

Method method = obj.getClass().getMethod().getMethod("test" + whichChild);
method.invoke(obj);

最好在Parent的接口上有一个可以调用的方法,并在子类中被覆盖。

public abstract class Parent {
  public void test() {
    System.out.println("Test from parent");
  }

  public abstract void testChild();
}

然后只需调用:

obj.testChild();

或者,正如 Emanuele Ivaldi 指出的那样,只需覆盖 ChildAChildB 中的 test 并直接调用它。

【讨论】:

  • 通过反射我可以调用方法testChildA 即使objParent in Parent obj = child.newInstance();?
  • 当然——你可以调用它——但这并不意味着它可以保证工作。 Method 与调用它的实例分离。例如,您可以调用method.invoke("string") - 这将导致运行时异常。由您来确保仅以有意义的方式调用它。
  • 另一种方法是检查对象的类并将其转换为正确的实现并调用正确的方法,它不灵活,它很糟糕,但它避免使用反射,我说它很糟糕吗?
【解决方案3】:

试试这个。

public class Driver {
    Parent func(Class child, String whichChild) throws Exception {
        // whichChild: "ChildA" or "ChildB"

        child.forName(whichChild);

        Object obj = child.newInstance();
        // cast obj to type of child and call the method "test" + whichChild
    }
}

【讨论】:

  • 那为什么还要将child 作为参数传递呢?如果您突出显示您实际更改的内容,而不是仅仅说“尝试这段代码而不做解释”,这会有所帮助。
  • 我同意先生的观点。将编辑我的答案,谢谢:)
【解决方案4】:

我对此表示怀疑。就编译器而言,任何 Class 实例都可以作为参数发送。

因此,对于编译器而言,没有证据表明此实例实际上是您发送的类型的实例。

【讨论】:

  • Class&lt;? extends Parent&gt; 限制它。
猜你喜欢
  • 2018-04-22
  • 1970-01-01
  • 1970-01-01
  • 2021-08-11
  • 1970-01-01
  • 1970-01-01
  • 2022-07-10
  • 1970-01-01
相关资源
最近更新 更多