在Java中转换为具体类和调用方法
假设我们有一个名为A
的基类和一些子类( B
, C
, D
等)。 大多数子类都有方法do()
但基类没有。 AA
类提供了一个名为getObject()
的方法,它将创建一个B
或C
或D
等的对象,但是将该对象作为类型A
返回。
如果此方法可用,如何将返回的对象强制转换为具体类型并调用其do()
方法?
编辑: 我不允许更改类A
,子类或AA
,因为我使用一个封闭的源API ..是的,它确实有一些设计问题,你可以看到。
我认为更好的想法是让A
类将do()
方法定义为抽象方法或具体的空方法。 这样你就不必做任何演员表了。
如果你不允许改变任何类,你可以定义一个类MyA extends A
,它定义了do()
方法和MyB
, MyC
,…和一个基本上做AA
所做的MyAA
,只是它返回MyB
, MyC
类型的对象….
如果这不好,那么我没有看到另一种方法,而不是检查返回的对象是否为B
类型并对B
进行强制转换等等。
您可以使用instanceof
进行测试并调用do()
方法:
A a = aa.getObject(); if (a instanceof B) { B b = (B) a; b.do(); } // ...
假设A
定义了do
,它不是私有的,你可以在没有强制转换的情况下调用它,无论AA
返回的子类。 这是多态性的特征之一。 在运行时,解释器将使用do
的正确(即实际类的实现)版本。
首先,使用do()
作为抽象方法将Class A
作为抽象类是更好的方法……
此外,如果你仍然想要你想要的方式……那么
做一个明确的演员。
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的Object Reference Variable
do()
,类A
必须具有 go()
方法。
如果您不允许更改A
但您可以更改子类,那么您可以使用方法do()
创建一个接口,并让所有子类实现该接口。
public interface Doer { public void do(); } public class B extends A implements Doer { //implement do method } //.. same for other subclass
那你就不需要演员。 否则你需要一些明确的向下转发。
您在描述的内容在我看来就像您想要在Base class
引用上调用Derived Class
方法。
但是,为此,您还需要在base class
使用您的方法。
所以,你需要在你的基类A
声明你的方法do()
。如果你不想给一个实现,让它是抽象的,或者让它成为一个空方法..这没关系..
现在,如果你做同样的事情你正在解释..你不需要做一个类型转换..
因为,将根据which derived class object does your base class reference point to
调用适当的Derived Class
方法
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
..这可能是一个主要问题..
最好的方法是使用A
类方法。 但是因为你不允许改变任何课程。 我建议你使用reflection在所有类周围创建一个包装器实例。
下面的类中的静态方法仅用于说明如何执行此操作。 你可以有单独的实例变量,它可以在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
。
如果方法调用返回有问题的类的实例,则可以通过一些工作来完成此操作,这是您的具体问题(上图)。
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 _ a(K value) {//Note that this is static return new _ (value);//So the IDE names aren't nasty } }
连锁的助手类。
/** * An instance method cannot override the static method from Chain, * which is why this class exists (ie to suppress IDE warnings, * and provide fluent usage). * * @author Gregory G. Bishop ggb667@gmail.com (C) 11/5/2013 all rights reserved. */ final class _ { public T a;//So we can reference the last value if desired. protected _(T t) { this.a = T; }//Required by Chain above public _ a(K value) { return new _ (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]