简体   繁体   English

从 static 获取子 class 父 class 在 Java 中的方法

[英]getting child class from static method of parent class in Java

Suppose I have these classes:假设我有这些课程:

public class ChildClass extends ParentClass
{
    // some class definition here
}


public abstract class ParentClass
{
    public static void printClass()
    {
        // get the class that extends this one (and for example, print it)
    }

    // some class definition here
}

Lets say when calling ParentClass.printClass() I want to print the name of the class (like doing System.out.println(ParentClass.class) ).假设在调用ParentClass.printClass()时我想打印 class 的名称(就像做System.out.println(ParentClass.class) )。 When then extending ParentClass (for example like in ChildClass ) and calling ChildClass.printClass() , I want it to print the name of the extending class (like doing System.out.println(ChildClass.class) ).然后扩展ParentClass (例如在ChildClass )并调用ChildClass.printClass()时,我希望它打印扩展的名称 class (就像做System.out.println(ChildClass.class) )。 Is this somehow possible?这有可能吗?

I've found a way to get the class from inside a static method by using MethodHandles.lookup().lookupClass() , but when using it inside of ParentClass.printClass and extending ParentClass, then calling printClass on the extending Class, I always get the class of ParentClass .我找到了一种通过使用MethodHandles.lookup().lookupClass()从 static 方法内部获取 class 的方法,但是当在ParentClass.printClass内部使用它并扩展 ParentClass,然后在扩展 Class 上调用printClass时,我总是得到 class 的ParentClass

Quoting @RealSkeptic :引用@RealSkeptic

Static methods are not inherited. Static 方法不被继承。 The fact that you can call ChildClass.printClass() is just syntactic sugar.您可以调用 ChildClass.printClass() 的事实只是语法糖。 It actually always calls ParentClass.printClass().它实际上总是调用 ParentClass.printClass()。 So you can't do something like that with a static method, only an inheritable non-static one.所以你不能用 static 方法做类似的事情,只能用一个可继承的非静态方法。

static methods are best thought of as living entirely outside of the class itself. static 方法最好被认为完全存在于 class 本身之外。 The reason they do show up in classes is because of the design of java (the language) itself: Types aren't just types with a hierarchy, they also serve as the primary vehicle for java's namespacing system.它们确实出现在类中的原因是 java(语言)本身的设计:类型不仅仅是具有层次结构的类型,它们还充当 java 命名空间系统的主要载体。

Types live in packages, packages are the top level namespace concept for types.类型存在于包中,包是类型的顶级命名空间概念。 So how do you refer to a method?那么如何引用方法呢? There's only one way: Via the type system.只有一种方法:通过类型系统。 Hence, static methods do have to be placed inside a type.因此,static 方法必须放在一个类型中。 But that's about where it ends.但这就是它结束的地方。

They do not inherit, at all.他们根本不继承。 When you write:当你写:

ChildClass.lookupClass()

The compiler just figures out: Right, well, you are clearly referring to the lookupClass() method in ParentClass so that is what I will compile.编译器只是弄明白了: 好吧,你显然指的是ParentClass中的lookupClass()方法,所以就是我要编译的内容。 You can see this in action yourself by running javap -c -p MyExample .您可以通过运行javap -c -p MyExample亲眼看到这一点。 The same principle applies to non-static methods, even.同样的原则甚至适用于非静态方法。

For instance methods, the runtime undoes this maneuvre: Whenever you invoke a method on any object, the runtime system will always perform dynamic dispatch;对于实例方法,运行时取消了这个操作:每当你在任何 object 上调用方法时,运行时系统将始终执行动态调度; you can't opt out of this.你不能选择退出。 You may write:你可以写:

AbstractList<String> list = new ArrayList<String>();
list.sort(someComparator);

and you can use javap to verify that this will end up writing into the class file that the method AbstractList::sort is invoked.并且您可以使用javap来验证这将最终写入调用方法 AbstractList::sort 的 class 文件。 But, at runtime the JVM will always check what list is actually pointing at - it's an instance of ArrayList, not AbstractList (that's obvious: AbstractList is abstract; no object can ever be directly instantiated as `new AbstractList).但是,在运行时,JVM 将始终检查实际指向的list - 它是 ArrayList 的实例,而不是 AbstractList(很明显:AbstractList 是抽象的;object 不能直接实例化为“new AbstractList”)。 If ArrayList has its own take on the sort method, then that will be called.如果 ArrayList 有自己的排序方法,那么将调用它。

The key takeaway of all that is: Static methods do not inherit, therefore, this dynamic dispatch system is not available to them, therefore, what you want cannot be done in that fashion.所有这一切的关键是:Static 方法不继承,因此,这个动态调度系统对它们不可用,因此,你想要的东西不能以那种方式完成。

So what to do?那么该怎么办?

It feels like what you're doing is attempting to associate a hierarchy to properties that apply to the class itself.感觉就像您正在做的是尝试将层次结构与适用于 class 本身的属性相关联。 In other words, that you want there to be a hierarchical relationship between the notion of 'ParentClass's lookupClass method and ChildClass's lookupClass method - lookupClass is not a thing you ask an instance of ChildClass or ParentClass - you ask it at the notion of the these types themselves.换句话说,您希望“ParentClass 的lookupClass方法和 ChildClass 的lookupClass方法的概念之间存在层次关系 - lookupClass 不是你问 ChildClass 或 ParentClass 的实例的东西 - 你在这些类型的概念中问它他们自己。

If you think about it for a moment, constructors are the same way.如果你想一想,构造函数也是一样的。 You don't 'ask' an instance of ArrayList for a new arraylist. You ask ArrayList, the concept.您不会向 ArrayList 的实例“询问”新的 arraylist。您询问 ArrayList,这个概念。 Both 'do not really do' inheritance and cannot be abstracted into a type hierarchy.两者都'不真正做' inheritance 并且不能抽象为类型层次结构。

This is where factory classes come in .这就是工厂类的用武之地

Factory classes as a concept are just 'hierarchicalizing' staticness, by removing static from it: Create a sibling type to your class hierarchy ( ParentClassFactory for example):工厂类作为一个概念只是“分层”静态,通过从中删除static :为您的 class 层次结构创建兄弟类型(例如ParentClassFactory ):

abstract class ParentClassFactory {
  abstract ParentClass create();
  abstract void printClass();
}

and then, in tandem with writing ChildClass , you also write ChildClassFactory .然后,在编写ChildClass的同时,您还编写了ChildClassFactory Generally factories have just one instance - you may want to employ the singleton pattern for this.通常工厂只有一个实例——您可能希望为此使用 singleton 模式。 Now you can do it just fine:现在你可以做得很好了:

class ChildClassFactory extends ParentClassFactory {
  private static final ChildClassFactory INSTANCE = new ChildClassFactory();
  public static ChildClassFactory instance() { return INSTANCE; }
  public ParentClass create() { return new ChildClass(); }
  public void printClass() { System.out.println(ChildClass.class); }
}

// elsewhere:

// actually gets the ChildClassFactory singleton:
ParentClassFactory factory = ....;
factory.printClass(); // will print ChildClass!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM