从超类中获取子类的名称


77

假设我有一个名为的基类Entity。在该类中,我有一个静态方法来检索类名称:

class Entity {
    public static String getClass() {
        return Entity.class.getClass();
    }
}

现在,我有另一个班级对此进行扩展。

class User extends Entity {
}

我想获取User的类名称:

System.out.println(User.getClass());

我的目标是看到“ com.packagename.User”输出到控制台,但是我将最终以“ com.packagename.Entity”结尾,因为直接从静态方法中引用了Entity类。

如果这不是静态方法,则可以通过使用类中的this关键字Entity(即:)轻松解决return this.class.getClass()。但是,我需要此方法来保持静态。有关如何处理此问题的任何建议?

Answers:


41

不可能。静态方法无论如何都不是运行时多态的。区分这些情况绝对是不可能的:

System.out.println(Entity.getClass());
System.out.println(User.getClass());

它们编译为相同的字节码(假设方法在中定义Entity)。

此外,您将如何以一种使它具有多态性的方式调用此方法?


1
感谢您的澄清,我想我对静态方法的编译方式还不了解。这有助于解决问题,我将不得不研究其他解决方案。
马特·哈金斯

2
+1,完全正确。整个问题源于对静态方法如何工作的误解。
马克·彼得斯2010年

94

不要将方法设为静态。问题是,当您调用时,getClass()您正在超类中调用该方法-静态方法不会被继承。此外,您基本上是在进行名称Object.getClass()混淆,这很令人困惑。

如果您需要在超类中记录类名,请使用

return this.getClass().getName();

拥有Entity实例时将返回“实体”,拥有实例时将返回“用户” User,依此类推。


1
this在静态方法中不存在。
马特·哈金斯

32
@Matt Huggins,这就是为什么我的回答中的第一句话说的是Don't make the method static
matt b 2010年

2
@ matt b-这就是为什么我的问题的倒数第二句话这么说However, I need this method to remain static.
Matt Huggins,2012年

@MattHuggins我想知道为什么Pojo方法不起作用。如果要调用静态方法,则必须引用代码中已经存在的类名。如果实例化了子类,但引用是超类的引用,则您有一个对象,不需要调用静态方法。
Mindwin 2015年

5
即使此答案未解决“但是,我需要此方法保持静态”,但如果您(像我一样)登陆此处寻找如何在不需要静态的方法中获取类,这将很有用。;)
Ryan Heathcote

6

您的问题模棱两可,但据我所知,您想从静态方法中了解当前类。类彼此继承的事实无关紧要,但出于讨论的考虑,我也以这种方式实现了它。

父类{
    公共静态无效printClass(){
      System.out.println(Thread.currentThread()。getStackTrace()[2] .getClassName());
    }
}

公共类测试扩展了父类{
    公共静态void main(String [] args){
      printClass();
    }
}

哎呀,那个stacktrace-hack很脏。这有什么错System.out.println(Parent.class.getName());
whiskeysierra

2
正如我所说,马特的问题是模棱两可的,我提供了可能的答案之一。显然,您的版本没有提供与我的代码相同的输出,因此无法进行比较-您正在谈论的是不同的解决方案。读取线程堆栈不是黑客,这是检查一个人的呼叫层次结构的一种正常方法(当然,我跳过了健全性检查,因为这是一个示例)。
Gilead 2010年

这是一个非常有趣的hack,但与请求的行为无关。此函数显示调用该方法的类的名称(即,如果删除extends Parent并更改了对的调用Parent.printClass(),它仍将显示“ Test”)。
nemetroid

6

这对我有用

this.getClass().asSubclass(this.getClass())

但是我不确定它是如何工作的。


3

超类甚至不应该知道子类的存在,更不用说基于子类的完全限定名称执行操作了。如果您确实需要根据确切的类是什么进行操作,并且无法通过继承执行必要的功能,则应该按照以下步骤进行操作:

public class MyClassUtil
{
    public static String doWorkBasedOnClass(Class<?> clazz)
    {
        if(clazz == MyNormalClass.class)
        {
            // Stuff with MyNormalClass
            // Will not work for subclasses of MyNormalClass
        }

        if(isSubclassOf(clazz, MyNormalSuperclass.class))
        {
            // Stuff with MyNormalSuperclass or any subclasses
        }

        // Similar code for interface implementations
    }

    private static boolean isSubclassOf(Class<?> subclass, Class<?> superclass)
    {
        if(subclass == superclass || superclass == Object.class) return true;

        while(subclass != superclass && subclass != Object.class)
        {
            subclass = subclass.getSuperclass();
        }
        return false;
    }
}

(未经测试的代码)

此类也不知道自己的子类,而是使用Class该类执行操作。它很可能仍会与实现紧密地联系在一起(通常是一件坏事,或者即使不是很糟,它也不是特别),但是我认为这样的结构比弄清楚其所有子类的超类更好。


2

为什么要实现自己的getClass()方法?你可以用

System.out.println(User.class);

编辑(详细说明):您希望方法是静态的。在这种情况下,您必须在要使用其类名的类上调用该方法,无论是子类还是超类。然后MyClass.getClass(),您可以直接致电MyClass.class或而不是致电MyClass.class.getName()

另外,您正在创建一个staticObject.getClass()实例方法具有相同签名的方法,该方法不会编译。


1
我故意写了这个问题,所以它在StackOverflow上是非常简陋的,直截了当。确实是因为我正在构建一个更加健壮的静态方法,该方法利用了扩展此抽象基类的任何子类的类名。
马特·哈金斯

1
听起来好像您希望通过static方法实现多态,但这是不可能的。另外,您能否详细说明为什么上述功能不够强大?
samitgaur's

它不够健壮,因为我必须在每个继承的类中重新定义静态方法,而不是仅仅能够定义一次静态方法。
马特·哈金斯

1
如果要使用静态,则已经知道具体的类。这有什么错User.class.getName()
whiskeysierra

因为如果我将代码硬编码User.class.getName()Entity的静态方法,那么如果我扩展Entity名为的新类会发生什么Profile呢?它将仍然返回User的类名,而不是Profile的类名。
马特·哈金斯

2
  1. 在超类中创建一个成员String变量。
  2. 将this.getClass()。getName()添加到将值存储在成员String变量中的构造函数中。
  3. 创建一个吸气剂以返回名称。

每次实例化扩展类时,其名称都将存储在String中,并可以通过getter访问。


0

静态方法与类相关联,而不与特定对象相关联。

考虑一下如果有多个子类,这将如何工作-例如,管理员也是一个实体。仅与Entity类相关联的静态Entity方法如何知道所需的子类?

你可以:

  • 使用现有的getClass()方法。
  • 将参数传递给静态getClass()方法,然后在该对象上调用实例方法。
  • 使您的方法为非静态方法,然后重命名。

0

如果我正确理解了您的问题,我认为您可以实现所需的唯一方法是在每个子类中重新实现静态方法,例如:

class Entity {
    public static String getMyClass() {
        return Entity.class.getName();
    }
}

class Derived extends Entity {
    public static String getMyClass() {
        return Derived.class.getName();
    }
}

这将打印package.Entity和package.Derived您所需。凌乱但嘿,如果那是你的限制...


0

如果我正确,您想在静态方法的基类中使用您的子类,我认为您可以通过将类参数传递给方法来实现

class Entity {
    public static void useClass(Class c) {
        System.out.println(c);
        // to do code here
    }
}

class User extends Entity {
}

class main{
    public static void main(String[] args){
        Entity.useClass(Entity.class);
    }
}

0

我的上下文:超类具有XML对象子类的实体。我的解决方案:在超类中创建一个类变量

Class<?> claz;

然后在子类中,我将在构造函数中设置超类的变量

public class SubClass {
   public SubClass() {
     claz = this.getClass();
   }
}

-4

这是非常简单的

User.getClass()。getSuperclass()


2
这与问题所要求的相反。我想要一个超类中的子类的名称。您的答案提供了子类中超类的名称。
马特·哈金斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.