如何“动态”将 Object 类型的实例转换为其特定的数据类型?
Posted
技术标签:
【中文标题】如何“动态”将 Object 类型的实例转换为其特定的数据类型?【英文标题】:How to "dynamically" cast an instance of Object type into its specific data type? 【发布时间】:2011-04-11 05:19:20 【问题描述】: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, e.g. 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 反射有帮助吗?
【问题讨论】:
【参考方案1】:高效且干净地处理此问题的最佳方法是让 foo 返回对象的持有者类。
abstract class Holder<T>
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<String>("")
public void doSomething()
;
else if (opt == 1) return new Holder<Integer>(1)
public void doSomething()
;
else if (opt == 2) return new Holder<Double>(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, e.g. from user input
//now I want to call doSomething method
h.doSomething();
【讨论】:
【参考方案2】:基本上,您希望在执行时执行重载解决方案 - 您将无法非常简单地做到这一点。
在某些情况下,visitor pattern 可以提供帮助,但我认为这里不会。我认为你被困在或者你在这里得到的代码,或者反射。我从来没有像我的一些同事那样热衷于访问者模式 - 总感觉有点乱 - 但值得考虑。
您能否让foo
调用正确的doSomething
重载而不是只返回值?这就是知道正在构造什么的代码——如果你可以通过适当的重载传递一个对象来调用doSomething
,你最终会在一个地方得到特定类型的逻辑。
在 Java 7 中,invokedynamic 可能在这种情况下很有用 - 当然 C# 4 中的 dynamic
类型会有所帮助 - 但我还没有研究足够的 invokedynamic 来确定。
【讨论】:
据我所知,Java 语言没有任何方法可以真正使用invokedynamic
字节码。不过,我想在这件事上被证明是错误的。
@Joachim:啊,我认为这是 Java 7 中提议的语言更改之一。老实说,我已经忘记了其中的内容和内容......【参考方案3】:
这里的问题可能是关注点分离之一。 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 返回了什么样的 Thing。
【讨论】:
foo 的返回类型必须是 Thingy。 :)【参考方案4】:Java 反射在一定程度上有所帮助,但缺少一条数据。此外,反射通常会引发许多您需要捕获的已检查异常。 (我在代码后面加了一个列表)
拥有“doSomething”方法的对象是什么?在这个例子中,我使用变量名“someObject”来表示持有“doSomething”方法的对象。你需要用这个来代替更有意义的东西。
另外,只是一个警告,这不会捕获派生类型,所以如果方法定义与给定的类型不匹配,你会得到一个方法未找到异常。
//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)
警告:以这种方式使用反射时需要处理以下异常:(顺便说一下,这不是一个不寻常的列表,反射通常在异常方面非常嘈杂)
NoSuchMethodException - if a matching method is not found or if the name is "<init>"or "<clinit>".
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.
【讨论】:
【参考方案5】:在 Java 中这样做没有任何意义。 Java 是静态类型的,如果您要动态转换它,则必须有一个 switch 语句来执行此操作,以便在不同对象上调用不同的方法。
示例——如果你有一个字符串或一个 int 并且你想“动态地”转换它(没有开关),你可以对它们执行什么操作而不需要不同的代码。
我想我的意思是,如果您必须进行强制转换,因为您想访问两个对象的不同之处(不同的方法),那么您如何在没有开关的情况下实际访问该不同的方法?
一个例外可能是内在变量——对于那些你想要泛型的人来说,但是在类之外使用内在变量是个坏主意。
哦,你可能真正想要的是让所有类实现相同的接口——然后你就不用强制转换了。
铸造应该是极其罕见的。
【讨论】:
以上是关于如何“动态”将 Object 类型的实例转换为其特定的数据类型?的主要内容,如果未能解决你的问题,请参考以下文章
java中如何把一个String类型的变量转换成double型的?
javascript怎样将object类型转换成array数组