声明变量 final 和 static

2022-09-02 01:35:58

此注释是在代码审查中做出的,并且做出此注释的人已不在我们的团队中。

任何必须由类装入器在运行时解析的类型都不应该具有由声明为 final 和 static 的引用所保存的实例。

下面是代码行:

private final static Logger log = LoggerFactory.getLogger(MyClass.class);

我熟悉将记录器声明为静态或非静态的争论,但此注释似乎更一般。我找不到任何解释为什么静态和最终是坏的。有人可以详细说明吗?


答案 1

该评论很可能与类加载器泄漏问题有关(这是一篇好文章)。

简而言之,这个问题发生在需要重新加载类加载器的环境中。如果通过类装入器动态装入类,然后尝试重装类装入器,则将静态 final 字段与通过类装入器创建的类的对象保留为一些,将防止卸载类装入器本身。发生这种情况后,您将获得.OutOfMemoryError

上面链接的文章列出了可能产生此行为的首要罪魁祸首之一,以及您可以采取的解决泄漏的措施(例如显式释放类加载器)。


答案 2

代码行完全没问题,并且没有真正的问题,因为变量是 和 。finalstatic

也许做出该评论的人对以下内容感到困惑。

在 Java 中,当您创建类型的变量(例如,它也适用于其他一些类型)时,编译器可能会在使用该变量的位置替换实际的常量值,而不是对变量的引用。例如,假设您有以下各项:public final staticint

class A {
    public final static int VALUE = 3;
}

public class B {
    public static void main(String[] args) {
        System.out.println(A.VALUE);
    }
}

当你编译并运行这个时,它显然会打印3。

现在假设您更改了类并设置了 .你会期望,如果你重新编译类,然后运行类(不重新编译类),你会看到。但是发生的事情是,您仍然会看到.这是因为在编译类 时,in 类被替换为实际的常量值。AVALUE = 4ABB43A.VALUEB3B

这是 Java 编译器对常量所做的优化。

如您所见,如果类的公共 API 中有此类常量,这可能会导致问题。如果更改此类常量的值,则代码的用户必须重新编译其代码。

但是在您在问题中发布的代码中,这不是问题,因为变量是.private

更多详情:

Java 语言规范 13.4.9


推荐