动力节点首页 全国咨询热线:400-8080-105

绑定手机号,登录
手机号

验证码

微信登录
手机号登录
手机号

验证码

微信登录与注册
微信扫码登录与注册

扫码关注微信公众号完成登录与注册
手机号登录
首页 > 文章

一个IDE的提示,引发了对《Java编程思想》的质疑?

03-29 15:12 1066浏览
举报 T字号
  • 大字
  • 中字
  • 小字

在slf4j的LoggerFactory类中有几个静态方法,方法的修饰为private final static。而IDE会提示,private的方法不用final修饰。

这个提示看起来很合理,既然方法为private的了,也就说是私有的,不可被继承,当然不可改变了,也就不需要再用final进行修饰了。

此刻问了自己一个为什么?虽然看起来是这么回事,但底层是如何实现的呢?是不是意味着private修饰的成员方法默认就是final的?

关于private方法不能被重写我们就不举例说明了,很显然的事。下面就来求证一下“private修饰的成员方法是不是默认就是final的”。

Java编程思想对final的定义

《Java编程思想》第4版,第267页中有描述“final和private关键字”的一段内容:

“类中所有的private方法都隐式的指定为是final的……可对private方法添加final修饰词,但这并不能给该方法增加任何额外的意义。”

从本质上来讲private是用来表示可见性的,而final是用来表示禁止覆盖的。JVM真的会对private隐式的指定为final吗?下面我们就写一段代码,并利用工具来进行证明一下。

证明过程

首先我们定义一个类,在类中定义两个方法,一个private修饰,一个private final修饰:

public class FinalMethod {

    private void test1(){
    }

    private final void test2(){
    }
}

然后,我们对类进行编译,看看编译之后的字节码中到底是如何实现的。

在class文件中,有专门描述方法的方法表,方法表第一项就是访问标志access_flags。这个标志用于识别一些类或接口层次的访问信息。具体标志位以及标志的含义如下:

关于access_flags可以参考《深入Java虚拟机》介绍类文件结构的章节。补充了基础知识之后,我们就通过工具来看看上面的类编译之后是什么样子。

这里用到一款开源的字节码浏览器工具:jclasslib bytecode viewer。通过该工具打开FinalMethod的class文件,先看test1方法:

可以看到该方法的access_flags访问标准为0x0002[private],对照上表的名称也就是ACC_PRIVATE。

那再看test2方法的access_flags的值:

可以看到对应的值为0x0012,对照上表并没有发行有这么一个值,它是怎么来的呢?其实access_flags如果有多个修饰的话,是会进行或(|)运算的,也就是0x0002 | 0x0010,结果不就是0x0012。对应的Flag名称就是ACC_PRIVATE和ACC_FINAL。

结论分析

通过上面的分析,如果说被private修饰的方法都隐式的指定为final的了,那么,编译的字节码应该是一致的才对。但通过上面的分析,很显然两者是有区别的。

也就是说,虽然我们知道private修饰的方法不用再使用final进行修饰了,但本质上它与private final修饰的方法还是有所区别的,不能一概而论。

小结

其实单从使用层面来讲,本篇文章的分析并没有太多的意义,使用时通过private修饰了,就不用再使用final了。只是说明slf4j源码在这个层面上是需要进行一定的优化的。

但如果你留意这个分析过程所牵涉的知识和工具,你是不是发现会收获很多?比如class文件的结构、访问标志、算法,以及字节码浏览器等等。

平时工作或学习中,多问一个为什么可能就会串联出一连串的知识点、工具和方法论,这也是学习和实践的一部分。

0人推荐
共同学习,写下你的评论
0条评论
代码小兵645
程序员代码小兵645

3篇文章贡献16602字

相关课程 更多>

作者相关文章更多>

推荐相关文章更多>

Git合并分支

代码小兵34507-28 11:08

Maven库的介绍

代码小兵65207-27 11:42

Maven打包详解

代码小兵12407-27 11:31

自定义Maven插件

代码小兵34507-27 11:50

导入Maven报错的解决方法

代码小兵69607-27 12:00

发评论

举报

0/150

取消