【问题标题】:Getting the name of a sub-class from within a super-class从超类中获取子类的名称
【发布时间】:2011-03-25 23:26:31
【问题描述】:

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

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

现在我有另一个类扩展它。

class User extends Entity {
}

我想获取用户的类名:

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

我的目标是看到“com.packagename.User”输出到控制台,但我最终会得到“com.packagename.Entity”,因为实体类是直接从静态方法引用的。

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

【问题讨论】:

    标签: java class subclass super superclass


    【解决方案1】:

    不要将方法设为静态。问题是,当您调用 getClass() 时,您正在调用超类中的方法 - 静态方法不会被继承。另外,你基本上是在给Object.getClass()命名,这令人困惑。

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

    return this.getClass().getName();
    

    当你有一个 Entity 实例时,这将返回“实体”,当你有一个 User 实例时返回“用户”,等等。

    【讨论】:

    • this 不存在于静态方法中。
    • @Matt Huggins,这就是为什么我的回答中的第一句话说Don't make the method static
    • @matt b - 这就是为什么我的问题倒数第二句说However, I need this method to remain static.
    • @MattHuggins 我想知道为什么 Pojo 方法不起作用。如果要调用静态方法,则必须引用代码中已经存在的类名。如果你已经实例化了子类,但引用是超类的,你有一个对象,不需要调用静态方法。
    • 即使这个答案没有解决“但是,我需要这个方法保持静态”,如果(像我一样)你登陆这里寻找如何在一个方法中获取类,它是有用的不需要是静态的。 ;)
    【解决方案2】:

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

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

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

    此外,您将如何以一种对多态有意义的方式调用此方法?

    【讨论】:

    • 感谢您的澄清,我想我对静态方法如何编译还不够了解。这有助于澄清问题,我将不得不研究替代解决方案。
    • +1,完全正确。整个问题源于对静态方法工作原理的误解。
    【解决方案3】:

    这对我有用

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

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

    【讨论】:

      【解决方案4】:

      您的问题含糊不清,但据我所知,您想通过静态方法了解当前类。类相互继承这一事实无关紧要,但为了便于讨论,我也以这种方式实现了它。

      类父{ 公共静态无效打印类(){ System.out.println(Thread.currentThread().getStackTrace()[2].getClassName()); } } 公共类测试扩展父{ 公共静态无效主要(字符串[]参数){ 打印类(); } }

      【讨论】:

      • 哎呀,那个 stacktrace-hack 很脏。 System.out.println(Parent.class.getName()); 怎么了?
      • 正如我所说,Matt 的问题含糊不清,我提供了一个可能的答案。显然,您的版本没有提供与我的代码相同的输出,因此无法进行比较——您正在谈论不同的解决方案。并且读取线程堆栈不是黑客,它是检查调用层次结构的一种正常方式(当然,我跳过了完整性检查,因为这是一个示例)。
      • 这是一个非常有趣的 hack,但与请求的行为无关。此函数打印调用该方法的类的名称(即,如果您删除extends Parent 并将调用更改为Parent.printClass(),它仍会打印“Test”)。
      【解决方案5】:

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

      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 类来执行操作。最有可能的是,它仍然会与实现紧密联系在一起(通常是一件坏事,或者如果还不错,它也不是特别),但我认为这样的结构比超类弄清楚什么要好它的所有子类都是。

      【讨论】:

        【解决方案6】:

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

        System.out.println(User.class);
        

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

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

        【讨论】:

        • 我故意写了这个问题,所以它在 StackOverflow 上是非常简单的,并且直接进入问题的重点。这真的是因为我正在构建一个更健壮的静态方法,它利用扩展这个抽象基类的任何子类的类名。
        • 听起来你想要通过static 方法实现多态性,这是不可能的。另外,你能详细说明一下为什么上面的内容不够健壮吗?
        • 它不够健壮,因为我必须在每个继承类中重新定义静态方法,而不是只能定义一次静态方法。
        • 如果你想使用静态,你已经知道具体的类了。 User.class.getName() 怎么了?
        • 因为如果我将User.class.getName() 硬编码到Entity 的静态方法中,那么如果我用一个名为Profile 的新类扩展Entity 会发生什么?它仍然会返回 User 的类名而不是 Profile 的类名。
        【解决方案7】:
        1. 在超类中创建成员 String 变量。
        2. 将 this.getClass().getName() 添加到将值存储在成员 String 变量中的构造函数中。
        3. 创建一个 getter 以返回名称。

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

        【讨论】:

          【解决方案8】:

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

          考虑如果有多个子类,这将如何工作——例如,Administrator 也是一个实体。您的静态 Entity 方法(仅与 Entity 类关联)如何知道您想要哪个子类?

          你可以:

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

          【讨论】:

            【解决方案9】:

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

            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。凌乱但嘿,如果这些是你的限制......

            【讨论】:

              【解决方案10】:

              如果我说得对,你想在静态方法的基类中使用你的子类 我认为您可以通过将类参数传递给方法来做到这一点

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

              【讨论】:

                【解决方案11】:

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

                Class<?> claz;
                

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

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

                【讨论】:

                  【解决方案12】:

                  这很简单

                  User.getClass().getSuperclass()

                  【讨论】:

                  • 这与问题要求的相反。我想从超类中获得子类的名称。您的答案提供了子类中超类的名称。
                  猜你喜欢
                  • 2014-01-07
                  • 1970-01-01
                  • 2012-03-23
                  • 1970-01-01
                  • 2011-01-20
                  • 1970-01-01
                  • 2016-06-25
                  • 2016-09-17
                  • 1970-01-01
                  相关资源
                  最近更新 更多