Java:抽象类中的静态字段

我只是从一个例子开始,最好的解释:

public abstract class A{ static String str; } public class B extends A{ public B(){ str = "123"; } } public class C extends A{ public C(){ str = "abc"; } } public class Main{ public static void main(String[] args){ A b = new B(); A c = new C(); System.out.println("b.str = " + b.str); System.out.println("c.str = " + c.str); } } 

这将打印出来:

b.str = abc

c.str = abc

但我想要一个解决scheme,其中每个实例化超类的子类都有自己类variables,同时我希望能够通过标识符引用该类variables,或者抽象超类中定义的方法调用。

所以我想输出是:

b.str = 123

c.str = abc

那可行吗?

如果你希望类B和C有单独的静态variables,你需要在这些类中声明variables。 基本上,静态成员和多态不会在一起。

请注意,通过引用访问静态成员在可读性方面是一个非常糟糕的主意 – 它看起来像是取决于引用的值,而不是真的。 所以当你将str移到B和C时,你的当前代码甚至不会编译。相反,你需要

 System.out.println("b.str = " + B.str); System.out.println("c.str = " + C.str); 

如果你确实需要多态访问这个值(即通过A的一个实例),那么一个选项就是创build一个多态的getter:

 public class A { public abstract String getStr(); } public class B extends A { private static String str = "b"; @Override public String getStr() { return str; } } 

(和C相同)。

通过这种方式,您可以根据每个实例没有单独的variables来获得所需的行为,但是您仍然可以多形地使用它。 对于一个实例成员来说,返回一个这样的静态值是有点奇怪的,但是你基本上使用了多态的值,

 public abstract class A { private String str; public String getStr() { return str;} protected void setStr(String str) { this.str = str; } } 

那么你将能够拥有

 B b = new B(); b.getStr(); 

setter和getter是我的补充,你可以通过简单地使variables非静态。

更新如果你想拥有每个子类的静态,那么你可以有:

 protected static Map<Class, String> values; public abstract String getValue(); 

接着:

 public String getValue() { values.get(getClass()); } public void setValue(String value) { values.set(getClass(), value); } 

但这通常是一个坏主意。

系统中只有一个静态variables实例。

在加载类之前,静态variables会在启动时加载到系统中。

原因是这两个时间abc打印是因为你的str的值设置为abc在最后。

这将打印你想要的输出:

 public abstract class A{ } public class B extends A{ static String str; public B(){ str = "123"; } } public class C extends A{ static String str; public C(){ str = "abc"; } } public class Main{ public static void main(String[] args){ A a = new B(); A c = new C(); System.out.println("B.str = " + B.str); System.out.println("C.str = " + C.str); } } 

既然你在子类中硬编码值或str ,你可以这样做:

 public abstract class A{ public abstract String getStr(); } public class B extends A{ public String getStr(){ return "123"; } } public class C extends A{ public String getStr(){ return "abc"; } } 

这会在你的情况下做的伎俩。

当然,那么你应该通过这样的方法来调用它:

 public class Main{ public static void main(String[] args){ A b = new B(); A c = new C(); System.out.println("b.str = " + b.getStr()); System.out.println("c.str = " + c.getStr()); } } 

将静态varibale放在每个子类中,并向抽象超类添加一个(不是静态的)抽象方法:

 abstract String getStr(); 

然后通过返回这个特殊子类的静态字段来实现每个子类中的getStr()方法。

 public class B extends A { private static String str; @Override public String getStr() { return B.str; } } 

这是我所做的,以避免必须在每个子类中实现相同的方法。 这是基于Bozho的答案。 也许它可以帮助某人。

 import java.util.HashMap; import java.util.Map; /** * * @author Uglylab */ public class SandBox { public static void main(String[] args) { A b = new B(); A c = new C(); System.out.println("b.str = " + B.getStr(b.getClass())); System.out.println("c.str = " + C.getStr(c.getClass())); } } abstract class A{ protected static Map<Class, String> values = new HashMap<>(); public static String getStr(Class<? extends A> aClass) { return values.get(aClass); } public static void setStr(Class<? extends A> aClass, String s) { values.put(aClass, s); } } class B extends A{ public B(){ setStr(this.getClass(),"123"); } } class C extends A{ public C(){ setStr(this.getClass(),"abc"); } } 

我认为有一种方法来解决这个问题,就是使用一个单一的类BC来模仿静态的方法和字段。 既可以扩展抽象类A ,也可以有自己的str值。