【问题标题】:Java: static field in abstract classJava:抽象类中的静态字段
【发布时间】: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

这可行吗?

【问题讨论】:

    标签: java static abstract


    【解决方案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..

          【讨论】:

            猜你喜欢
            • 2011-04-02
            • 1970-01-01
            • 2014-06-19
            • 2012-10-01
            • 1970-01-01
            • 2015-08-31
            • 2012-12-03
            • 1970-01-01
            • 2011-11-15
            相关资源
            最近更新 更多