2010-08-05 127 views
54

假设我有一个名为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类是直接从静态方法引用的。

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

回答

36

不可能。静态方法不以任何方式运行时多态。这是绝对不可能区分这些情况:

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

他们搜集到相同的字节码(假设该方法在Entity定义)。

此外,你会如何以这种方式调用这个方法,使其具有多态性?

+1

感谢澄清,我想我不知道如何静态方法编译。这有助于解决问题,我将不得不寻找替代解决方案。 – 2010-08-05 19:04:47

+2

+1,完全正确。整个问题源于对静态方法工作原理的误解。 – 2010-08-05 19:28:59

2

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

System.out.println(User.class); 

编辑(详细阐述了一下):你想的方法是静态的。在这种情况下,你必须调用你想要的类名的类的方法,无论它是子类还是超级类。然后,不要致电MyClass.getClass(),您可以致电MyClass.classMyClass.class.getName()

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

+1

我故意写了这个问题,所以它会在StackOverflow上变得非常枯燥,直接问到这个问题。这是因为我构建了一个更强大的静态方法,该方法利用任何子类的类名扩展此抽象基类。 – 2010-08-05 18:32:26

+1

听起来就像你想通过静态方法进行多态,这是不可能的。另外,你能否详细说明为什么上述不够强大? – samitgaur 2010-08-05 18:40:52

+0

它不够健壮,因为我不得不在每一个继承类中重新定义静态方法,而不是只能定义一次静态方法。 – 2010-08-05 18:53:23

67

不要让该方法为静态。问题在于,当调用getClass()时,您正在调用超类中的方法 - 静态方法不会被继承。另外,你基本上是名字阴影Object.getClass(),这很混乱。

如果您需要登录超类中的类名,使用

return this.getClass().getName(); 

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

+1

'this'不存在静态方法。 – 2010-08-05 19:03:49

+24

@Matt Huggins,这就是为什么我的答案中的第一句话说'不要让方法静态' – 2010-08-05 20:10:44

+2

@ matt b - 这就是为什么我的问题的倒数第二句说'但是,我需要这种方法来保持静态。' – 2012-01-19 02:05:32

0

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

请考虑如果有多个子类 - 例如,管理员也是一个实体,这将如何工作。你的静态实体方法如何与实体类相关联,知道你想要哪个子类?

,你可以:

  • 利用现有的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(); 
    } 
} 

这将打印包。实体和包装。根据需要提供。凌乱但嘿,如果那些是你的限制...

6

你的问题是模棱两可的,但据我可以告诉你想从静态方法知道当前类。类之间相互继承的事实是无关的,但为了讨论的缘故,我也是这样实现的。

 
class Parent { 
    public static void printClass() { 
     System.out.println(Thread.currentThread().getStackTrace()[2].getClassName()); 
    } 
} 

public class Test extends Parent { 
    public static void main(String[] args) { 
     printClass(); 
    } 
} 
+0

哎哟,* stacktrace-hack *很脏。 'System.out.println(Parent.class.getName())有什么问题;'? – whiskeysierra 2010-08-05 19:03:53

+2

正如我所说,马特的问题是不明确的,我提供了一个可能的答案。很明显,你的版本并没有给出与我的代码相同的输出,所以没有比较 - 你正在谈论一个不同的解决方案。 阅读线程堆栈不是破解,它是检查一个调用层次结构的正常方式(当然,我跳过了理智检查,因为这是一个例子)。 – Gilead 2010-08-05 19:11:47

+0

这是一个非常有趣的黑客攻击,但与请求的行为没有多大关系。这个函数打印类的名字*调用方法(即,如果你删除'extends Parent'并将调用改为'Parent.printClass()',它仍然会打印“Test”)。 – nemetroid 2017-07-25 09:27:09

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类来执行操作。最有可能的是,它仍然与实现紧密相连(通常是坏事,或者即使不坏也不是,特别是),但我认为像这样的结构比超类更好地搞清楚它的所有子类是什么。

-4

它是由

User.getClass()。getSuperclass之类()

+2

这与所要求的问题相反。我想要一个超类内的子类的名称。你的答案在一个子类中提供了超类的名字。 – 2012-10-10 00:25:32

2
  1. 创建在超类中的成员字符串变量非常简单的完成。
  2. 将this.getClass()。getName()添加到将值存储在成员String变量中的构造函数中。
  3. 创建一个getter来返回名称。

每次扩展类被实例化时,它的名字将被存储在字符串中并且可以被getter访问。

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

这对我的作品

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

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