Java:抽象类中的静态字段

时间:2011-02-04 13:56:14

标签: java static abstract

我刚开始讲一个例子,最能解释一下:

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

可行吗?

8 个答案:

答案 0 :(得分:48)

如果希望类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相同)。

通过这种方式,您可以获得所需的行为,而不是每个实例都有单独的变量,但您仍然可以多态地使用它。实例成员返回这样的静态值有点奇怪,但你使用的是类型的多态,基本上......

答案 1 :(得分:6)

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是我的补充,你可以简单地使变量非静态。

更新如果您想拥有static-per-subclass,那么您可以拥有:

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);
}

但这通常是一个坏主意。

答案 2 :(得分:3)

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

abstract String getStr();

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

public class B extends A {
 private static String str;

  @Override
  public String getStr() {
    return B.str;
  }
}

答案 3 :(得分:2)

系统中只存在一个静态变量实例。

静态变量将在加载类之前加载到系统中。

打印时间abc的原因是因为你将str的值设置为最后的abc。

答案 4 :(得分:2)

这将打印您想要的输出:

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);
    }
}

答案 5 :(得分:2)

由于您无论如何硬编码子类中的值或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());
    }
}

答案 6 :(得分:1)

我所做的就是避免必须在每个子类中实现相同的方法。它基于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");
    }
}

答案 7 :(得分:0)

我认为解决这个问题的一种方法是使用类BC的单例来模仿静态方法和字段。这两者都可以扩展抽象类A,但它们的值为str ..