假设我们有一个名为A
的基类和一些子类(B
,C
,D
等)。大多数子类都有方法do()
,但基类没有。
类AA
提供了一个名为getObject()
的方法,该方法将创建类型为B
或C
或D
等的对象,但会将对象返回为输入A
。
如果此方法可用,如何将返回的对象强制转换为具体类型并调用其do()
方法?
编辑:
我不允许更改类A
,子类或AA
的实现,因为我使用的是封闭的源API ..是的,它确实有你可以看到一些设计问题。
答案 0 :(得分:3)
我认为更好的想法是让类A
将do()
方法定义为抽象方法或具体的空方法。这样你就不用做任何演员了。
如果您不允许更改任何类,那么您可以定义一个类MyA extends A
来定义do()
方法和MyB
,MyC
,...以及MyAA
基本上会执行AA
所做的事情,只需返回MyB
,MyC
类型的对象....
如果这不行,那么除了检查返回的对象是否为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]