如何从基类实例中找出子类?

17

有没有办法从一个基类实例中找出派生类的名称?

例如:

class A{
    ....
}
class B extends A{
    ...
}
class c extends A{
    ...
}

现在如果一个方法返回一个A对象,我能否找出它是否是类型BC


9
请注意,类型嗅探有点像代码异味。并不是总是做错事,但它确实错误的情况很多,所以你应该仔细检查自己的设计。如果可能的话,使用多态(但也请参考Steve Yegge的文章When Polymorphism Fails)。 - outis
baseInstance.getClass().getName() - paiego
7个回答

25

可以使用 instanceofClass#getClass() 方法。

A returned = getA();

if (returned instanceof B) { .. }
else if (returned instanceof C) { .. }

getClass()方法会返回以下其中之一:A.classB.classC.class

如果在if语句中,你需要进行向下转型 - 即:

((B) returned).doSomethingSpecificToB();

尽管如此,有时使用 instanceof 或 getClass()被认为是一种不良实践。您应该使用多态性来尝试避免检查具体子类的需要,但根据提供的信息,我无法告诉您更多。


1
关于在这种情况下使用多态的说明:您可以在A的实现中拥有一个名为getType()或类似的方法,并在BC中覆盖该方法。由于Java中的所有方法都是虚拟的,对getType()的调用将解析特定的子类型。 - aioobe

5

您有尝试过使用 instanceof 吗?

例如:

Class A aDerived= something.getSomethingDerivedFromClassA();

if (aDerived instanceof B) {

} else if (aDerived instanceof C) {

}

//Use type-casting where necessary in the if-then statement.

4

回答你的问题:

有没有办法从基类对象中找出派生类的名称?

没有,超类无法告诉子类的名称/类型。

您必须询问对象(它是子类的实例)并询问它是否是特定子类的 instanceof,或调用它的 getClass() 方法。


2
您可以在子类的构造函数中完成此操作。
class A {
    protected String classname;
    public A() { this.classname = "A"; }
    public String getClassname() { return this.classname; }
}
class B extends A {
    public B() {
        super();
        this.classname = "B";
    }
}

所以
A a = new A();
a.getClassname(); // returns "A"
B b = new B();
b.getClassname(); // returns "B"
((A)b).getClassname(); // Also returns "B"

由于它被转换为“A”对象,因此它将调用“A” getClassname() 函数,但返回的是由构造函数设置的“B”构造函数的值。
注意:在设置之前调用super();

0
有没有办法从基类实例中找出派生类的名称?
正如这里所回答的那样,您可以使用这种非常简单的方法。
abstract class A {
    public final String getName() {
         return this.getClass().getName();
    }
}

class B extends A { }

class C extends A { }

然后只需打印当前的class名称:

B b = new B();
C c = new C();

System.out.println(b.getName());
System.out.println(c.getName());

输出:

com.test.B
com.test.C

不需要存储额外的字符串,检查instanceof或在任何子类中override该方法。


0

我能想到两种方法: 1)使用Java反射API 2)另一种是使用instanceOf

另一种方法可以是将对象与对象进行比较,我不知道它可能是什么样子的,你可以试试这个。


0
一种更现代的方法(Java 16+)是使用模式匹配来处理 instanceof 运算符。语法非常简单:
if(x instanceof X xChild){
    // use xChild
}

它既更短,也更少出错,因为它将测试变量(上面的示例中的x)的运行时类型、向下转换和分配给新变量(上面的示例中的xChild)的所有步骤结合在一起。阅读更多

另一个例子:

    public void addUIControl(UIControl control) {
        if(control instanceof SelectList sl){
            selectList = sl;
        }
        else if(control instanceof TextBox tb){
            textBox = tb;
        }
        else if(control instanceof Button btn){
            button = btn;
        }
        else {
            throw new IllegalArgumentException("Uknown UIControl object has been passed to the SendFormMediator");
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接