声明变量final和static

sdo*_*oca 22 java classloader

此评论是在代码审核中进行的,而制作该评论的人不再在我们的团队中.

在运行时必须由类加载器解析的任何类型都不应该具有被声明为final和static的引用保持的实例.

这是代码行:

private final static Logger log = LoggerFactory.getLogger(MyClass.class);
Run Code Online (Sandbox Code Playgroud)

我熟悉声明loggers静态或非静态的争论,但这个评论似乎更为通用.我找不到为什么静态和最终都不好的任何解释.有人可以详细说明吗?

das*_*ght 13

评论很可能与Classloader Leaking的问题有关(这是一篇好文章).

简而言之,这个问题发生在需要重新加载类加载器的环境中.如果通过类加载器动态加载类,然后尝试重新加载类加载器,则使用通过此类加载器创建的类的对象保留静态最终字段将阻止卸载类加载器本身.一旦发生这种情况,你就得到了OutOfMemoryError.

上面链接的文章列出了可能产生此行为的顶级罪魁祸首之间的日志库,以及可以用来解决泄漏的措施(例如显式释放类加载器).


Jes*_*per 12

代码行完全正常,没有真正的问题,因为变量是finalstatic.

也许发表评论的人对以下内容感到困惑.

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

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

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

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

现在假设你改变了类A并设置了VALUE = 4.你会期望,如果你重新编译类A然后运行类B(没有重新编译类B),你会看到4.但是会发生什么,你仍然会看到3.这是因为A.VALUE在编译类时,in class B被实际的常量值替换.3B

这是Java编译器为常量所做的优化.

如您所见,这可能会导致问题,如果您在类的公共API中有这样的常量.如果更改此类常量的值,代码的用户将不得不重新编译代码.

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

更多细节:

Java语言规范13.4.9