在Java中,我如何显式引用`this`类的静态成员?

时间:2014-10-24 02:28:30

标签: java override static-members

在Java中,如何明确引用this类的静态成员?

我想明确地引用静态成员以获得可读性,但是不要使用文字类名来尊重重写该值的子类。

一个人为的例子:

class Flying {
   static final String label = "A Flying Superhero";
   String exclamation() {
      return "Look! Up in the sky! It’s a bird! It’s a plane! It’s "+(WHAT GOES HERE?)+"!";
   }
}

class Superman extends Flying {
   static final String label = "Superman";
}
class Howard extends Flying {
   static final String label = "Howard the Duck";
}

请注意,我想避免单独使用label,因为它的含义可能不明确;我希望读者立即知道它是一个静态成员,就像它们来自Flying.label,但没有命名基类。

(在启发这个问题的情况下,静态成员也是最终成员,但我认为这不会影响你如何引用它。)


编辑:这是一个可能更具吸引力的案例。我想在超类中实现main,并让它创建并使用被调用的子类的实例。

class Super
   public static void main( String[] args ) {
      Super instance = new (?WHAT GOES HERE?)( /*...*/ );
      instance.use();
   }
}

class Sub extends Super {
   void use() {
      /* ... */
   }
}

当jvm在Sub上启动时,我希望它使用相同的main实现,但是使用子类的实例。

这种情况的不同之处在于上下文是静态的,要访问的静态成员是构造函数。

(这是在建模和模拟的研究生课程中进行的家庭作业;超类是一个模型,不同的场景被实现为子类。)

要澄清问题,我认为需要做三件事:

  • 在静态方法的调用中,获取调用该方法的类(我没有找到任何内容)
  • 给定一个类,访问该类的静态成员(可能使用aClass.getDeclaredField?)
  • 给定一个Class,构造该类的新实例(可能带有aClass.getConstructors?)

结论

在读到答案之前,我没有意识到我正在尝试做一些与Java方式相反的事情。显然我已经习惯了更多动态语言。 (感觉我被JavaScript宠坏了似乎是错误的。)

这种架构很大程度上取决于我正在使用的框架提供的GUI,它为您提供了一个类选择器,然后是一个UI,用于与您选择的类的实例进行交互。这使得使用不同场景的便捷方式可以为每个场景创建一个类。

对于限制访问静态成员的原始情况,目前使用文字类名称已经足够了。

对于涉及实例化的编辑案例,我将实例化留在子类中并将实例传递给超类的方法,如下所示:

class Model {
   public static void run( Model m ) {
      /* ... */
   }
}

class Scenario extends Model {
   public static void main( String[] args ) {
      Model.run( new Scenario( /*...*/ ) );
   }
}

将来,我会尽量避免将某些图书馆引入与语言功能冲突的领域。

2 个答案:

答案 0 :(得分:2)

您无法覆盖变量,相反,您需要提供一种方法,例如......

class Flying {

    private final String label = "A Flying Superhero";

    String exclamation() {
        return "Look! Up in the sky! It’s a bird! It’s a plane! It’s " + getLabel() + "!";
    }

    public String getLabel() {
        return label;
    }
}

class Superman extends Flying {

    private final String label = "Superman";
    @Override
    public String getLabel() {
        return label;
    }

}

class Howard extends Flying {

    private final String label = "Howard the Duck";
    @Override
    public String getLabel() {
        return label;
    }
}

答案 1 :(得分:1)

子类不继承静态成员。在您的新示例中,main可以像Sub Sub.main(args);一样引用,但它始终属于Super。您甚至可以检查堆栈跟踪,确认它是在Super上调用的。

  • 在静态方法的调用中,获取调用该方法的类(我没有找到任何内容)

这不可能。

  • 给定一个类,访问该类的静态成员(可能使用aClass.getDeclaredField?)

这可以做到,但如果你只使用常规继承,那么解决一个非常简单的问题是一种非常麻烦的方式。

  • 给定一个Class,构造该类的新实例(可能带有aClass.getConstructors?)

这可以做到并且不时有用。现在使用Java 8 Supplier不太有用,例如SomeClass::new

静态是在Java中处理这种问题的错误方法。常规继承可以让您轻松地完成这些工作。

class InterfacesExample {
    public static void main(String[] args) {
        @SuppressWarnings("unchecked") // Arrays#asList
        List<Class<? extends Printer>> classes = Arrays.asList(
            FruitPrinter.class,
            TreePrinter.class
        );

        for(Class<? extends Printer> cls : classes) {
            try {
                Constructor<? extends Printer> ctor = cls.getDeclaredConstructor();
                Printer p = ctor.newInstance();
                p.print();
            } catch(Exception e) {
                System.err.println(e);
            }
        }
    }
}

interface Printer {
    void print();
}

class FruitPrinter implements Printer {
    @Override
    public void print() {
        System.out.println("Apple, Banana, Plum, Pear");
    }
}

class TreePrinter implements Printer {
    @Override
    public void print() {
        System.out.println("Oak, Maple, Elm, Willow");
    }
}