【问题标题】:Java static fields not working with inheritanceJava 静态字段不适用于继承
【发布时间】:2013-04-24 20:10:29
【问题描述】:

好吧,这可能很简单,但我就是不明白。

    package foo.foo.foo;

public class Vars {
    public static boolean foo = false;
}

好的,这就是我的 Vars 课程。

然后我有一个 JFrame,带有一个 JMenuBar、JMenu 和一个 JMenuItems。

  items = new JCheckBoxMenuItem("Foo");
        items.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                AbstractButton ab = (AbstractButton)e.getSource();
                Vars.foo = ab.getModel().isSelected();
                System.out.println(Vars.foo);
            }
        });
    menu.add(items, 0);
    menuBar.add(menu,0);

一切都很好,它为 println 返回 true。 现在,这是实际的问题部分...... 我有一个 if 语句 if(Vars.foo) 这 - 应该 - 工作,对吧?它从不执行 if 括号内的代码,除非我在它上面添加这行代码。

System.out.println(Vars.foo);

这自然打印为 true,然后 if 语句有效,但如果我注释掉该行,它就不起作用。

我也一直在谷歌搜索,并尝试过这个:

Vars v = null;
if(v.yoo)

除非我有 println,否则它仍然不会这样做,我不知道为什么 println 使它工作。你能解释一下为什么/如何工作吗?

编辑:

public class painthandling implements Runnable {
@Override
public void run() {
    Vars y = null;
    while(true){
        if(y.foo){
            //some code here
        }
        System.out.println(y.foo);

    }
}

}

这是不工作的部分,if 语句。总是返回 false。

       frame f = new frame();
       (new Thread(new painthandling())).start();
        System.out.print("Got it.");

JFrame 部分在新框架中被调用,然后另一个类在那里被调用,Vars 类在两者中被调用。在painthandling()中,if语句如果没有println则返回false。

【问题讨论】:

  • 你能贴出你说不起作用的代码吗?
  • 你的问题的继承部分在哪里?
  • 我仍然看不到继承...无论如何,为什么字段首先是静态的?让(可能)多个线程访问静态字段似乎是一个非常的坏主意。
  • 你怎么知道代码没有被执行?更有可能它正在运行而你没有意识到它
  • 如果我没有把它当作静态的,它就会出错,到处都是。我试过使它成为非静态的,并做 Vars v = null; v.foo,但我得到了相同的结果至于运行,我有 printlns 没有被解雇。

标签: java oop inheritance static field


【解决方案1】:

简答:将变量设为volatile

长答案:

我做了一些测试,实际上我可以重现你的情况(至少我认为是一样的)。考虑这段代码:

public class Test {
    public static boolean foo = false;

    public static void main(String[] args) {

        new Thread(new Runnable(){

            @Override
            public void run() {
                while(true) {
                    try {
                        Thread.sleep(2000);
                        System.out.println("Swapping");
                        Test.foo = !Test.foo;
                    }
                    catch(Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

        while(true) {
            if(Test.foo) {
                System.out.println("I'm here");

            }

        }

    }
}

这永远不会打印I'm here。但是,正如 OP 所述,在 while 循环中添加 System.out.println 确实会使其打印出来。但有趣的是,它可以是任何 println 语句。它不需要打印变量值。所以这行得通:

public class Test {
    public static boolean foo = false;

    public static void main(String[] args) {

        new Thread(new Runnable(){

            @Override
            public void run() {
                while(true) {
                    try {
                        Thread.sleep(2000);
                        System.out.println("Swapping");
                        Test.foo = !Test.foo;
                    }
                    catch(Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

        while(true) {
            if(Test.foo) {
                System.out.println("I'm here");

            }
            System.out.println(""); // Doesn't have to be System.out.println(Test.foo);
            // This also works (lock is just an object)
            // synchronized(lock) {
            //     int a = 2;
            // }

        }

    }
}

还有一些其他情况也会产生“预期”输出,那就是创建变量 volatile,或者在完成测试的 while 循环内执行 Thread.sleep()System.out.println 时它起作用的原因可能是因为 println 是同步的。事实上,在循环内进行任何同步操作都具有相同的效果。总而言之,这是一个线程(内存模型)问题,可以通过将变量标记为volatile 来解决。但这并不能改变使用静态变量进行多线程访问是一个坏主意的事实。

我建议阅读Chapter 17 of the Java Language Specification 以了解有关线程、同步和 Java 内存模型的更多信息。

【讨论】:

    【解决方案2】:

    我并没有真正阅读您的帖子,但在浏览后看起来您正在尝试使用这样的静态方法。

    someMethod() {
        Var var = null;
        boolean bool = var.foo
    }
    

    静态方法和字段的好处是你不必实例化它们,试试这个吧:

    someMethod() {
        boolean bool = Var.foo
    }
    

    【讨论】:

    • 确实如此,但与实际问题无关。
    • 投了反对票,但无论如何我猜想 sys out 调用会触发编译器优化代码并修复 if 循环中的错误。
    • 很抱歉。没有消极的意思。只是指出问题是别的。他访问变量的方式(按实例或按类)不应该有任何区别。您可能对 sys 输出是正确的,但真正的问题可能与线程有关。
    • 我之前把所有东西都放在一个线程上,但仍然导致同样的问题,我认为不是线程问题。
    猜你喜欢
    • 1970-01-01
    • 2010-11-03
    • 2012-06-21
    • 1970-01-01
    • 2011-04-02
    • 2013-10-20
    • 2015-02-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多