在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
?)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( /*...*/ ) );
}
}
将来,我会尽量避免将某些图书馆引入与语言功能冲突的领域。
答案 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
?)这可以做到,但如果你只使用常规继承,那么解决一个非常简单的问题是一种非常麻烦的方式。
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");
}
}