6

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

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

编辑: 我不允许更改 Class A、子类或AA的实现,因为我使用的是封闭的 Source API。是的,它确实存在一些设计问题,如您所见。

4

8 回答 8

4

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

A a = aa.getObject();
if (a instanceof B) {
   B b = (B) a;
   b.do();
}
// ...
于 2012-10-01T16:05:25.887 回答
3

我认为更好的主意是让类将方法A定义do()为抽象方法或具体的空方法。这样你就不必做任何演员。

如果您不允许更改任何类,那么您可以定义一个MyA extends A定义do()方法的类 and MyB, MyC,... 和一个MyAA基本上可以做的事情AA,只是它返回类型为MyB, MyC...的对象。

如果这不行,那么除了检查返回的对象是否是类型B并进行强制转换B等之外,我没有看到其他方法。

于 2012-10-01T16:04:20.163 回答
1

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

于 2012-10-01T16:04:28.057 回答
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每个子类。这可能是一个主要问题。

于 2012-10-01T16:09:01.590 回答
0

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

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

做一个明确的演员表。

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

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

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();

-要调用类型 Ado()的方法Object Reference Variable,类A 必须具有该 go()方法。

于 2012-10-01T16:10:14.733 回答
0

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

public interface Doer {
    public void do();
}

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

//.. same for other subclass

那你就不需要演员表了。否则,您将需要一些明确的向下转换。

于 2012-10-01T16:13:27.070 回答
0

最好的方法是使用A该方法。但是由于您不允许更改任何课程。我建议您使用反射围绕所有类创建一个包装器实例。

下面类中的静态方法仅用于展示如何做到这一点。您可以有单独的实例变量,可以将 A 包裹在 E 中。

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您必须检查类型然后转换它。

于 2012-10-01T17:03:35.757 回答
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]
于 2013-11-05T22:23:34.910 回答