有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何将对象类型的实例“动态”转换为其特定的数据类型?

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反射有用吗


共 (5) 个答案

  1. # 1 楼答案

    在Java中这样做没有任何意义。Java是静态类型的,如果要动态转换它,必须有一个switch语句才能这样做,以便在不同的对象上调用不同的方法

    例如——如果您有一个字符串或int,并且希望“动态”强制转换它(不带开关),那么您可以对这两个字符串或int执行什么不需要不同代码的操作

    我想我是说,如果你必须强制转换,因为你想访问两个对象不同的东西(一个不同的方法),那么你怎么能在没有开关的情况下访问这个不同的方法呢

    一个例外可能是内在变量——对于那些想要泛型的人来说,但是在类之外使用内在变量是个坏主意

    哦,你可能真正想要的是让所有的类实现同一个接口——然后你就不用强制转换了

    铸造应该是非常罕见的

  2. # 2 楼答案

    高效、干净地处理此问题的最佳方法是让foo为对象返回holder类

    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();
    }
    
  3. # 3 楼答案

    基本上,您希望在执行时执行重载解析—您不可能简单地做到这一点

    一些情况下,visitor pattern可以帮助,但我认为在这里不会。我想你被困在或者这里的代码,或者反射。我从来没有像我的一些同事那样热衷于访客模式——它总是感觉有点凌乱——但值得一想

    你能让foo调用正确的doSomething重载而不是仅仅返回值吗?这是一段知道正在构造什么的代码——如果您可以通过适当的重载向它传递一个对象来调用doSomething,那么您将在一个地方得到特定于类型的逻辑

    在Java 7中,InvokedDynamic可能在这种情况下很有用——当然C#4中的dynamic类型会有所帮助——但我还没有对InvokedDynamic进行足够的研究来确定这一点

  4. # 4 楼答案

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

    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返回了什么样的东西

  5. # 5 楼答案

    Java反射有些帮助,但缺少一段数据。此外,反射通常会抛出许多需要捕获的已检查异常。(我在代码后面加了一个列表)

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

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

    //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.