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"); } }
我认为有一种方法来解决这个问题,就是使用一个单一的类B
和C
来模仿静态的方法和字段。 既可以扩展抽象类A
,也可以有自己的str
值。