我能从Java中的超类知道扩展类吗?

我能从Java中的超类知道扩展类吗?,java,inheritance,Java,Inheritance,我有以下课程 public class Super{ public static void useSubClass(){ //I want to access the sub class object here, how. } } public class Sub1 extends Super{ } public class Sub2 extends Super{ } 我想从超类中的静态方法访问子类对象。i、 e.当我调用Sub1.useSubClass()时,该方

我有以下课程

public class Super{

  public static void useSubClass(){
     //I want to access the sub class object here, how.
  }
}

public class Sub1 extends Super{

}

public class Sub2 extends Super{

}
我想从超类中的静态方法访问子类对象。i、 e.当我调用
Sub1.useSubClass()
时,该方法可以访问
Sub1.class
,当我使用
Sub2.useSubClass()
时,我可以访问
Sub2.class

public static void useSubClass(Super sub) {
    if (sub instanceof Sub1) {
        // Do something
    } else if (sub instanceof Sub2) {
        // Do something else
    } else {
        // Something else is extending Super
    }
}

是否有任何方法可以从超类访问子类对象。

一般来说,您不能从超类(也不应该!)访问子类对象,因为您不知道(也不应该假设!)哪些类将从您的超类继承

根据您想要做的事情,有其他选择,例如:

  • 使用定义子类必须实现的“填充方法”;这些填充方法将由超类中的模板方法调用
  • 定义要由子类重写的方法
  • 定义子类要实现的接口

更新:正如@JB Nizet所指出的,我可能误解了这个问题

如果希望从超类中的静态方法访问子类,可以执行以下操作(非常类似于):

  • 在您的超类中定义一个静态侦听器列表,将其称为
    list observerList
  • 在超类的构造函数中,将类实例本身添加到该静态
    observerList
  • 对于所有子类,它们都有责任从构造函数中调用
    super()
    ,以便将自己注册到
    observerList
    (并在解构器中注销)
  • 然后在超类的static
    useSublass()
    方法中,您可以迭代子类实例列表,找到您关心的特定实例(可能由某个参数指定),然后对其进行处理

不,您不能,因为超类不能知道子类的方法。
您应该考虑创建一个新的类,该类既可以看到超级类,也可以看到子类,在这个新类中实现静态方法

不继承静态方法,调用<代码>子2 .UsSub类(<)>代码>严格等同于调用<代码> Suth.UsSub类(<)/代码> . 无法获取此信息,因为它不存在。编译器允许调用
Sub2.useSubclass()
,但将其转换为
Super.useSubclass()


然而,一个更好的问题是为什么?您不能简单地重写子类中的方法吗?

请注意,您可以在Python中使用类方法执行此操作:

class super(object):
    @classmethod
    def usesubclass(cls):
        print cls

class sub1(super):
    pass

class sub2(super):
    pass
使用此代码,您可以调用
sub1.usesubclass()
sub2.usesubclass()
,这将分别打印
sub1
sub2
类的表示:

>>> sub1.usesubclass()
<class '__main__.sub1'>
>>> sub2.usesubclass()
<class '__main__.sub2'>

然后将该方法显式调用为
Super.useSubClass(Sub1.class)
Super.useSubClass(Sub2.class)

,尽管可以创建对该超类的引用并将其指向任何子类。这也可以在运行时动态完成。这是运行时多态性的一种方式。

我发现了一些问题。如果小心实施,它会起作用

/** SuperClass.java **/
public abstract class SuperClass {

    public static void printClass(){
    System.out.println(new ImplementingClassRetriever().getCallingClass());
    }

    static class ImplementingClassRetriever extends SecurityManager{
    public Class getCallingClass() {
        Class[] classes = getClassContext();
        for (Class clazz : classes) {
        if (SuperClass.class.isAssignableFrom(clazz) && clazz != null
            && !clazz.equals(SuperClass.class)) {
            return clazz;
        }
        }
        return null;
    }
    }
}


/** Main.java **/
public class Main{
    public static void main(String[] args) {
    Sub.printClass(); //this does not work
    Sub.testStaticCall(); //this works!! :)
    }
}


class Sub extends SuperClass{

    public static void testStaticCall(){
    Sub.printClass(); //calling the method in the super class
    }
}
这只是一个玩具的例子。超类包含一个静态类,该类包含检索调用类的方法

在子类中,我有另一个静态方法,它调用超类的方法来打印类名


Main
类/函数包含对
Sub
的继承和本地实现方法的两个调用。第一个调用打印为null,因为调用上下文(即Main)不是
Super
的子类,但是
Sub
中的委托方法可以工作,因为调用上下文现在是
SuperClass
的子类,因此可以确定调用类。

调用静态方法时根本没有实例。你的问题没有多大意义。超类不知道扩展它的类。为什么不调用Sub1.getClass()@谢谢。我也有同样的怀疑。我只是想在rails中实现一个类似于超级ActiveRecord的类。想一想,问是否有一些东西在反思或者我不知道的东西。我想你误解了这个问题。OP没有调用实例方法,而是静态方法。我看不出当代码调用
Sub2.useSubclass()
时,您的更新如何允许识别Sub2.class,尤其是在从未构造过任何类的实例的情况下。如果必须将参数传递给该方法,则只需调用
Sub2.useSubclass(Sub2.class)
,解决方法是只使用提供的参数。不需要所有这些破碎的访客资料。@JBNizet更新了我的答案,添加了一些关于使用观察者列表的内容,但仍然有点粗糙。它不仅粗糙,而且完全破碎,没有必要。请阅读我之前的评论。静态方法不会被重写。为什么该方法具有静态属性?为什么。这就是要求。该方法在类上被调用,因此它们需要是静态的。
/** SuperClass.java **/
public abstract class SuperClass {

    public static void printClass(){
    System.out.println(new ImplementingClassRetriever().getCallingClass());
    }

    static class ImplementingClassRetriever extends SecurityManager{
    public Class getCallingClass() {
        Class[] classes = getClassContext();
        for (Class clazz : classes) {
        if (SuperClass.class.isAssignableFrom(clazz) && clazz != null
            && !clazz.equals(SuperClass.class)) {
            return clazz;
        }
        }
        return null;
    }
    }
}


/** Main.java **/
public class Main{
    public static void main(String[] args) {
    Sub.printClass(); //this does not work
    Sub.testStaticCall(); //this works!! :)
    }
}


class Sub extends SuperClass{

    public static void testStaticCall(){
    Sub.printClass(); //calling the method in the super class
    }
}