在Java中转换为具体类和调用方法

时间:2012-10-01 16:02:29

标签: java inheritance reflection types casting

假设我们有一个名为A的基类和一些子类(BCD等)。大多数子类都有方法do(),但基类没有。 类AA提供了一个名为getObject()的方法,该方法将创建类型为BCD等的对象,但会将对象返回为输入A

如果此方法可用,如何将返回的对象强制转换为具体类型并调用其do()方法?

编辑: 我不允许更改类A,子类或AA 的实现,因为我使用的是封闭的源API ..是的,它确实有你可以看到一些设计问题。

8 个答案:

答案 0 :(得分:3)

我认为更好的想法是让类Ado()方法定义为抽象方法或具体的空方法。这样你就不用做任何演员了。

如果您不允许更改任何类,那么您可以定义一个类MyA extends A来定义do()方法和MyBMyC,...以及MyAA基本上会执行AA所做的事情,只需返回MyBMyC类型的对象....

如果这不行,那么除了检查返回的对象是否为B类型并对B进行强制转换等等,我看不到另一种方法。

答案 1 :(得分:3)

您可以使用instanceof进行测试并调用do()方法:

A a = aa.getObject();
if (a instanceof B) {
   B b = (B) a;
   b.do();
}
// ...

答案 2 :(得分:1)

假设A定义do,并且它不是私有的,你可以在没有强制转换的情况下调用它,无论AA返回的子类。这是多态性的特征之一。在运行时,解释器将使用do的正确版本(即实际类的实现)。

答案 3 :(得分:0)

在我看来,您想要在Derived Class引用上调用Base class方法。

但为此,您需要在base class中使用您的方法 因此,您还需要在基类do()中声明方法A。如果您不想提供实现,请将其设为抽象,或者将其设置为空方法。没关系......

现在,如果你做同样的事情,你要解释..你不需要进行类型转换..

因为,将根据 - Derived Class

调用适当的which derived class object does your base class reference point to方法
public abstract class A {
   public abstract void do();
}

public class B extends A {
   public void do() {
       System.out.println("In B");
   }
}

public class Test {
    public static void main(String[] args) {
        A obj = returnA();

        obj.do();  // Will invoke class B's do() method
    }

    /** Method returning BaseClass A's reference pointing to subclass instance **/
    public static A returnA() {
         A obj = new B();
         return obj;
    }
}

好的,刚刚看到你的编辑,你不能改变你的课程..

在这种情况下,您实际上需要根据返回的引用实例执行typecast

因此,在上面的main方法中,A obj = returnA();此行之后添加以下行: -

if (obj instanceof B) {
    B obj1 = (B) obj;

}

但是,在这种情况下,您需要在每个子类上检查instanceof。这可能是一个主要问题..

答案 4 :(得分:0)

首先,将Class A作为抽象类使用do()作为抽象方法,这是一种更好的方法......

此外,如果你仍然想要你想要的方式......那么

做一个明确的演员。

B b = (B) a; // a is a casted back to its concrete type.

此外,您应该记住编译器的这一非常重要的行为

The Object Reference Variable of Super Type must have the method to be called, whether the Sub Type Object has or not.

<强>例如

A a = new B();

- 要在类型A的do()上调用方法Object Reference Variable,类A 必须具有 {{1方法。

答案 5 :(得分:0)

如果不允许更改A但您可以更改子类,则可以使用方法do()创建接口,并让所有子类实现该接口。

public interface Doer {
    public void do();
}

public class B extends A implements Doer {
    //implement do method
}

//.. same for other subclass

然后你不需要演员。否则你需要一些明确的向下转发。

答案 6 :(得分:0)

最好的方法是使用A类方法。但是因为你不允许改变任何课程。我建议你使用反射在所有类周围创建一个包装器实例。

下面的类中的静态方法仅用于说明如何操作。您可以使用单独的实例变量,它可以在E中包装A.

public class E {

public static void doMethod(A a) {
    Class<?> class1 = a.getClass();
    Method method;
    try {
        method = class1.getDeclaredMethod("doMethod", null);// B, C, D has doMethod
        method.invoke(a, null);
        // I know to many exceptions
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }

}
}

第二个选项是instance of,您必须检查该类型然后再进行投射。

答案 7 :(得分:0)

如果方法调用返回有问题的类的实例,那么你可以做一些工作,这是你的具体问题(上图)。

import static java.lang.System.out;

public class AATester {
   public static void main(String[] args){
      for(int x: new int[]{ 0, 1, 2 } ){
         A w = getA(x);
         Chain.a(w.setA("a")).a(
            (w instanceof C ? ((C) w).setC("c") : null );
         out.println(w);
      }
   }

   public static getA(int a){//This is whatever AA does.
      A retval;//I don't like multiple returns.
      switch(a){
         case 0:  retval = new A(); break;
         case 1:  retval = new B(); break;
         default: retval = new C(); break;
      }
      return retval;
   }
}

测试类A

public class A {
   private String a;
   protected String getA() { return a; }
   protected A setA(String a) { this.a=a; return this; }//Fluent method
   @Override
   public String toString() {
      return "A[getA()=" + getA() + "]";
   }
}

测试类B

public class B {
   private String b;
   protected String getB() { return b; }
   protected B setB(String b) { this.b=b; return this; }//Fluent method
   @Override
   public String toString() {
      return "B[getA()=" + getA() + ", getB()=" + getB() + "]\n  " 
      + super.toString();
  }
}

测试类C

public class C {
   private String c;
   protected String getC() { return c; }
   protected C setC(String c) { this.c=c; return this; }//Fluent method
   @Override
   public String toString() {
      return "C [getA()=" + getA() + ", getB()=" + getB() + ", getC()=" 
             + getC() + "]\n  " + super.toString();
   }
}

连锁课

/**
 * Allows chaining with any class, even one you didn't write and don't have 
 * access to the source code for, so long as that class is fluent.
 * @author Gregory G. Bishop ggb667@gmail.com (C) 11/5/2013 all rights reserved. 
 */
public final class Chain {
   public static <K> _<K> a(K value) {//Note that this is static
      return new _<K>(value);//So the IDE names aren't nasty
   }
}

Chain的助手类。

/** 
 * An instance method cannot override the static method from Chain, 
 * which is why this class exists (i.e. to suppress IDE warnings, 
 * and provide fluent usage). 
 *
 * @author Gregory G. Bishop ggb667@gmail.com (C) 11/5/2013 all rights reserved.
 */
final class _<T> {
   public T a;//So we can reference the last value if desired.
   protected _(T t) { this.a = T; }//Required by Chain above
   public <K> _<K> a(K value) {
      return new _<K>(value);
   }
}

输出:

    A [get(A)=a]
    B [get(A)=a, getB()=null]
      A [getA()=a]
    C [getA()=a, getB()=null, getC()=c)]
      B [get(A)=a, getB()=null]
      A [get(A)=a]