如何“动态”将Object类型的实例强制转换为其特定的数据类型?

public Object foo(int opt){ if (opt == 0) return new String(); else if (opt == 1) return new Integer(1); else if (opt == 2) return new Double(1); else if ... .. and many more } public void doSomething(String s){..} public void doSomething(Integer i){..} public void doSomething(Double d){..} ... and many more doSomething method public static void main(String[] args){ ... Object o = foo(x); //x is a value obtained during runtime, eg from user input //now I want to call doSomething method // (1) if (o instanceof String) doSomething((String) o); else if (o instanceof Integer) doSomething((Integer) o); else if (o instanceof Double) doSomething((Double) o); ... // (2) } 

有没有更好的方法来简化(1)…(2)所包含的语句?
Java Reflection有帮助吗?

有效和干净地处理这个问题的最好方法是让foo返回对象的持有者类。

 abstract class Holder { private final T object; protected Holder(T object) { this.object = object; } public T get() { return object; } public abstract void doSomething(); } public Holder foo(int opt) { if (opt == 0) return new Holder("") { public void doSomething() { } }; else if (opt == 1) return new Holder(1) { public void doSomething() { } }; else if (opt == 2) return new Holder(1.0) { public void doSomething() { } }; // many more } public static void main(String... args) throws IOException { Holder h = foo(x); //x is a value obtained during runtime, eg from user input //now I want to call doSomething method h.doSomething(); } 

这里的问题可能是关注点分离。 Java是一种面向对象的语言,它可能有助于以面向对象的方式尝试解决问题。 在这种情况下,您可能会问为什么main应该关注什么类型的Object o。 相反,您可能会考虑使用一组类,每个类都知道如何以自己的方式执行某些操作。

 abstract class Thing { abstract void doSomething(); } class IntegerThing extends Thing { public void doSomething() { /*whatever*/ }; } class FloatThing extends Thing { public void doSomething() { /*whatever*/ }; } //Then later: int foo(int type) { if(type == 0) return new IntegerThing(0); if(type == 1) return new FloatThing(7.5); if(type == 3) return new StringThing("Florence"); } int main(String args[]) { Thing something = foo(x); something.doSomething(); } 

你的foo()方法实际上变成了一个工厂,从那时起你就不再需要关心foo返回了什么样的东西了。

基本上你想要在执行时执行重载决策 – 你不能简单地做到这一点。

某些情况下, 访问者模式可以提供帮助,但我不认为它会在这里。 我认为你要坚持使用你在这里得到的代码,或者反思。 我从来没有像一些同事那样热衷于访客模式 – 总觉得有点乱 – 但是值得一想。

你能让foo调用正确的doSomething重载而不是只返回值吗? 这就是知道正在构造什么的代码 – 如果你可以传递一个对象来通过适当的重载调用doSomething ,你最终会在一个地方找到特定于类型的逻辑。

在Java 7中,invokedynamic可能在这种情况下很有用 – 当然C#4中的dynamic类型会有所帮助 – 但我还没有足够好地调查invokedynamic。

Javareflection有所帮助,但缺少一些数据。 此外,reflection通常会抛出您需要捕获的许多已检查exception。 (我在代码后面列出了一个列表)

持有“doSomething”方法的对象是什么? 在这个例子中,我使用变量名“someObject”来表示持有“doSomething”方法的对象。 你需要用它代替更具感性的东西。

此外,只是一个警告,这将不会捕获派生类型,因此如果方法定义与给定的类型不匹配,您将获得一个方法未找到exception。

 //now I want to call doSomething method // (1) Method method = someObject.getClass.getMethod("doSomething",new Class[] {o.getClass()}); method.invoke(someObject, new Object[] {o}); // (2) 

警告:当以这种方式使用reflection时,您需要处理以下exception:(顺便提一下,这不是一个不寻常的列表,reflection通常在exception方面非常嘈杂)

 NoSuchMethodException - if a matching method is not found or if the name is ""or "". NullPointerException - if name is null SecurityException - if access to the information is denied. IllegalAccessException - if this Method object enforces Java language access control and the underlying method is inaccessible. IllegalArgumentException - if the method is an instance method and the specified object argument is not an instance of the class or interface declaring the underlying method (or of a subclass or implementor thereof); if the number of actual and formal parameters differ; if an unwrapping conversion for primitive arguments fails; or if, after possible unwrapping, a parameter value cannot be converted to the corresponding formal parameter type by a method invocation conversion. InvocationTargetException - if the underlying method throws an exception. NullPointerException - if the specified object is null and the method is an instance method. ExceptionInInitializerError - if the initialization provoked by this method fails. 

在Java中执行此操作没有任何意义。 Java是静态类型的,如果你要动态地转换它,你必须有一个switch语句才能调用不同对象上的不同方法。

示例 – 如果您有一个字符串或一个int,并且您想要“动态”转换它(没有开关),那么对于不需要不同代码的两个操作,您可以执行什么操作。

我想我是说如果你因为想要访问两个对象不同的东西(一个不同的方法)而必须进行强制转换,那么如何在没有开关的情况下实际访问那个不同的方法呢?

一个例外可能是内在变量 – 对于那些你想要generics的人来说,但是在类之外使用内部变量无论如何都是个坏主意。

哦,你真正想要的是让所有的类都实现相同的接口 – 然后你就不用了。

铸造应该是非常罕见的。