Java:抽象类中的静态字段
Posted
技术标签:
【中文标题】Java:抽象类中的静态字段【英文标题】:Java: static field in abstract class 【发布时间】:2011-06-21 09:19:21 【问题描述】:我只是从一个例子开始,它解释得最好:
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
但我想要一个解决方案,其中每个实例化超类的子类都有自己的自己的类变量,同时我希望能够通过标识符引用该类变量,或者在抽象超类中定义的方法调用。
所以我希望输出是:
b.str = 123
c.str = abc
这可行吗?
【问题讨论】:
【参考方案1】:如果您希望类 B 和 C 具有单独的静态变量,则需要在这些类中声明变量。基本上,静态成员和多态性不能一起使用。
请注意,通过引用访问静态成员在可读性方面真的是个坏主意 - 它看起来就像它取决于引用的值,当它没有。因此,当您将 str
移至 B 和 C 时,您当前的代码甚至无法编译。相反,您需要
System.out.println("b.str = " + B.str);
System.out.println("c.str = " + C.str);
如果您确实需要多态访问值(即通过 A 的实例),那么一种选择是制作多态 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 也一样)。
这样你就可以得到你想要的行为,因为每个实例没有单独的变量,但你仍然可以多态地使用它。实例成员返回这样的静态值有点奇怪,但是您正在使用该值来实现类型的多态性,基本上......
【讨论】:
我的经验是,设置 Eclipse 将它们标记为编译错误甚至是值得的。 @biziclop:我也是。这就是为什么我首先在 Eclipse 中请求它:bugs.eclipse.org/bugs/show_bug.cgi?id=21109 :) 为什么这个答案没有被标记为解决问题? 但是如果我想在抽象类的静态方法中引用str
,既然getter是一个实例方法,我该怎么做呢?
@CameronHudson:你不能,而且你需要确切地指定你想要静态变量来自哪个类。从根本上说,在不了解更多背景信息的情况下很难给出建议。我建议您提出一个具有详细背景的新问题 - 您的要求与 8 年前这个问题的要求完全相同的可能性非常小。【参考方案2】:
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 是我添加的,你可以简单地将变量设置为非静态。
更新如果你想拥有每个子类的静态,那么你可以拥有:
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);
但这通常是个坏主意。
【讨论】:
即使没有 getter 和 setter 也可以。然后只需确保 str 变量是公开的,不建议这样做。 @Thijs:比起直接访问静态字段,我总是更喜欢一种方法(尤其是像getStr()
这样的只读方法)。
谢谢!不知道为什么你认为这是一个坏主意。有了这个解决方案,我什至不必在子类中编写任何代码,一切都在超类中实现。当然,在对象上调用方法来设置类变量(或者像你的解决方案那样伪造它,有点)看起来有点奇怪。但似乎无论如何都没有办法逃脱(Jon Skeet 和 Ralph 的解决方案)。
@Bozho:你能解释一下为什么这是个坏主意吗?
这很不自然,违反了最小惊讶原则:)【参考方案3】:
将静态变量放在每个子类中,并在抽象超类中添加(非静态)抽象方法:
abstract String getStr();
然后通过返回这个特殊子类的静态字段,在每个子类中实现getStr()方法。
public class B extends A
private static String str;
@Override
public String getStr()
return B.str;
【讨论】:
我编辑了我的帖子,是一个错误..对不起。问题是,我需要每个对象都引用一个值,该值在同一子类的所有对象之间共享,但不一定在不同子类的对象之间。【参考方案4】:系统中只有一个静态变量实例。
静态变量将在加载类之前的开始加载到系统中。
两次打印 abc 的原因是因为您在最后一次将 str 的值设置为 abc。
【讨论】:
【参考方案5】:这将打印你想要的输出:
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);
【讨论】:
谢谢。快到了:) 见拉尔夫的回答。可能是我解释得不好。【参考方案6】:由于您在子类中硬编码值或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());
【讨论】:
【参考方案7】:我这样做是为了避免在每个子类中实现相同的方法。它基于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");
【讨论】:
【参考方案8】:我认为解决此问题的一种方法是对B
和C
类使用单例来模仿静态方法和字段。两者都可以扩展抽象类A
,但会有自己的值str
..
【讨论】:
以上是关于Java:抽象类中的静态字段的主要内容,如果未能解决你的问题,请参考以下文章