【问题标题】:Is the ordering of static members sensitive in Swing?Swing 中静态成员的排序是否敏感?
【发布时间】:2011-05-27 14:20:36
【问题描述】:

我有这门课,比如说Foo。它extends JFrame 是一个单身人士。话虽如此,它有两个静态字段:1)Foo 的实例和 2)Color

这是Foo的代码sn-p:

public class Foo extends JFrame{
    private static final Color FOO_RED = new Color(155, 64, 69);
    private static final Foo INSTANCE = new Foo();

    private Foo(){
        //do stuff
    }

    public static Foo getInstance(){
        return INSTANCE;
    }
}

我还有另一堂课,比如说Launcher。这是负责启动应用程序的主类。这是一个简单的类,它唯一的工作就是将构造Foo 的任务委托给EDT

这是Launcher的代码sn-p:

public class Launcher{
    public static void main(String[] args){
        SwingUtilities.invokeLater((new Runnable(){
            @Override
            public void run()
            {
                Foo.getInstance();
            }
        }));
    }
}

现在,这一切都很好。 但是,当我切换Foo 的字段顺序时(见下文),使用FOO_RED 的组件不再被涂成这种颜色。

public class Foo extends JFrame{
    private static final Foo INSTANCE = new Foo(); //declared before Color
    private static final Color FOO_RED = new Color(155, 64, 69);

    private Foo(){
        //do stuff
    }

    public static Foo getInstance(){
        return INSTANCE;
    }
}

那么,这就引出了一个问题,静态字段的顺序对于Swing是否重要?

【问题讨论】:

    标签: java swing singleton static-members


    【解决方案1】:

    如前所述,静态字段的顺序确实很重要。按它们出现的顺序执行。

    我将对这个示例进行另一个更改。这将使您的静态字段顺序不那么重要。

    更新:使用IDOH (Initialization on Demand Holder) 模式使单例线程安全。

    private static class FooHolder {
        private static final Foo INSTANCE = new Foo();
    }
    
    public static Foo getInstance(){
        return FooHolder.INSTANCE;
    }
    

    【讨论】:

    • +1 仅在第一次需要时初始化实例。
    • +1,解释了为什么我看到了“古怪”的行为,并提供了一个合理的解决方案。谢谢你,basszero。 :)
    • 有两件事值得注意:@basszero 你离开了INSTANCE final(由Howard 指出),因此它不能被分配两次(初始化为null)。 @mre 这种方法是 not 线程安全的。在这种特殊情况下,这不是问题,因为您只使用该方法一次,并且始终来自事件线程(始终是同一个线程)。但是,如果另一个线程要访问它,那么它可能会接收到不同的实例。值得注意的是,确保您不会在整个线程代码中继续这种形式的“延迟初始化”。
    • @pickypg 很好,适合我懒惰。我通常将 IDOH 模式用于我的单身人士。
    【解决方案2】:

    是的。任何static 字段/块的排序问题。


    编辑: 首先,静态字段被设置为它们的默认值(所以FOO_REDnull)。然后静态字段按照它出现的顺序被初始化。所以可以在初始化之前观察FOO_RED字段。

    【讨论】:

    • @mre 而​​且它并不特定于 Swing。
    • 所以既然FOO_RED用于Foo的构造,如果我在声明FOO_RED之前构造Foo的实例,它不会使用它吗?我有点困惑,如果排序很重要,为什么没有编译时错误,甚至没有运行时错误。
    • @mre:首先,将静态字段设置为其默认值(FOO_RED 为空)。然后按出现的顺序初始化静态字段。因此可以在初始化之前观察 FOO_RED 字段。
    【解决方案3】:

    顺序对于静态字段很重要,因为它们是从上到下初始化的。在您的情况下,切换顺序会导致在 FOO_RED 初始化之前调用 Foo() 构造函数。因此,FOO_RED 将是 null 以在构造函数中使用。这是合法的,但显然对任何想使用 FOO_RED 的控件没有用处。

    【讨论】:

    • 这很奇怪。似乎应该抛出一些“依赖”错误(编译时或运行时)。
    • @mre Runtime 我认为不会起作用,因为它必须“向前看”才能看到在初始化之前使用了该字段。我相信编译器也没有捕捉到它,因为它假定所有静态初始化程序都将在任何实例构造函数之前运行。您基本上通过在静态初始化块中调用 Foo() 构造函数来“欺骗”它。如果是一系列方法调用导致了这种情况,那么检查这种情况可能会变得相当复杂,因此它只是忽略它并愉快地使用空引用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-08
    • 1970-01-01
    • 1970-01-01
    • 2016-05-03
    • 2013-05-10
    • 2010-11-04
    • 2011-01-24
    相关资源
    最近更新 更多