`
ZangXT
  • 浏览: 119356 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

无聊:谁说private方法自动是final的?兼评《Java编程思想》中的几个问题

阅读更多

          首先声明,本文无任何实际价值,只是讨论一些无聊的说法。

    有一个著名的帖子《Java关键字finalstatic使用总结》,里面有这样一句话:

注意:父类的private成员方法是不能被子类方法覆盖的,因此private类型的方法默认是final类型的。

    这句话的确值得注意,搞不明白一个表示可见性的关键字private和一个表示禁止覆盖的关键字final怎么扯上关系了。

    我说这句话是在java语义的角度看是错误的。有人说《Java编程思想》里这么说的,应该可信。如果你认为是错误的,如何证明?

    其实从语义角度很容易说明它们是不相关的了,证明也不难。我们知道,在class文件中,方法在常量池中有专门的项进行描述。

        method_info {

 

 


         u2 access_flags;

         u2 name_index;

         u2 descriptor_index;

         u2 attributes_count;

         attribute_info attributes[attributes_count];

    }

    其中access_flags描述方法的访问标志和属性,具体信息有:

Flag Name

Value

Interpretation

ACC_PUBLIC

0x0001

Declared public; may be accessed from outside its package.

ACC_PRIVATE

0x0002

Declared private; accessible only within the defining class.

ACC_PROTECTED

0x0004

Declared protected; may be accessed within subclasses.

ACC_STATIC

0x0008

Declared static.

ACC_FINAL

0x0010

Declared final; may not be overridden.

ACC_SYNCHRONIZED

0x0020

Declared synchronized; invocation is wrapped in a monitor lock.

ACC_NATIVE

0x0100

Declared native; implemented in a language other than Java.

ACC_ABSTRACT

0x0400

Declared abstract; no implementation is provided.

ACC_STRICT

0x0800

Declared strictfp; floating-point mode is FP-strict

 

    如果说“private类型的方法默认是final类型的”是正确的,那么自然,如果一个方法是private的,它的access_flags中应该存在

ACC_PRIVATEACC_FINAL,如果不存在ACC_FINAL则自然证明了该说法的错误。

   怎么看呢?找工具吧。

   http://www.ej-technologies.com/products/jclasslib/overview.html

   jclasslib是不错的工具。

   我们写一个简单的测试类:

public class Main {

    private void test(){}

    private final void test2(){}

}

编译,使用jclasslib打开Main.class文件。容易辨别。 

test():

test2():

 

    如果语言角度有“自动是……”这个语义的话,应该会自己添加相应的描述信息的。比如,我们说一个接口中的方法自动是public abstract 的,即使你不写,编译器也会自动添加的。比如下面例子:

public interface Main { void test(); }


 test()方法的描述符是:

 

    补充说明:在回复信息中,有一种说法是“private自动是final的”是为了内联优化。我们知道,final的方法可以内联(inline)优化,private的和static的也可以进行同样的优化。

这里要注意逻辑关系,private和static的可以进行内联优化,并不能说它们就是final的。其实final不过是语言级别的一个概念而已,它是内联的充分不必要条件。如果说,可以内联优化就是final的话,那么static的呢?可惜从语言角度我们无法说明private和final无关。只能从侧面说明一下:

class Base {
    public static final void test() {
    }
}

class Derived extends Base {
    public static void test() {
    }
}

    上面代码编译错误,因为final的存在。

    这起码能够说明,不要从内联角度来说“private方法自动为final的”。

 

 

    我感觉《Thinking In Java》上很多地方是值得推敲的。

    比如《Everything is an Object》一节,作者将存储区分为寄存器、栈、堆、常量区和非内存存储等5个部分,

当然,这是没有问题的。但是放到一个讲java的地方就有些奇怪了,毕竟java里提到的堆、栈一般来讲指的是面向

jvm的逻辑意义上的堆和栈,而且在这个层次上,内存的划分是由jvm规范定义的,包括pc寄存器、虚拟机栈、堆、

方法区、常量池、本地方法栈等。好像书里还提到过静态存储区的概念,这个jvm里也是不存在的。

   书里还指出“构造方法是static的”:

   Even though it doesn’t explicitly use the static keyword, the constructor is actually a

static method. So the first time an object of type Dog is created, or the first time a

static method or static field of class Dog is accessed, the Java interpreter must

locate Dog.class, which it does by searching through the classpath.

  

   实在搞不清楚作者为什么要说constructor是静态的,如果是的话,构造方法里还能用this吗

        此外还有一段争论“pass by value”了,作者在注释里有一段说明,我总感觉他有狡辩的意思。不好直接说作者的说法是错误的,不过感觉没有必要老在一些说法上标新立异。

       关于创建派生类对象,书里有这样的说法:When you create an object of the derived class, it contains within it a subobject of the base class.

This subobject is the same as if you had created an object of the base class by itself. It’s just that from the outside, the subobject of the base

class is wrapped within the derived-class object.

       好像别的资料里都没有“subobject”这样的说法。作者的这种想法估计是从C++来的。但我想java的设计者们并没有这么考虑。

首先,我们看在父类的构造函数中调用被子类覆盖的方法时的表现。在java中,我们不提什么“父类subobject”之类的说法,

创建的就是一个完整的对象,那就是派生类的对象,很自然的,在父类构造方法中调用的覆盖方法会是当前对象对应的重写过的方法,

因此此时就出现了多态现象。而不会根据“父类subobject”的类型去找方法。但是C++中确实是根据“父类subobject”的类型去找

方法的,因此不会出现多态现象。其次,在java中,实际的对象都需要包含一些标志信息,比如垃圾回收标志、线程锁标志等。

显然所谓的“父类subobject”是不会有这种信息的,从这个角度看,也没有必要非要制造“父类subobject”这样一个概念。

文字比较拗口,示例代码如下

public class Test {

    public static void main(String[] args) {

        new Derived();

    }

}

class Super {

    public Super() {

        test();

    }

    public void test() {

        System.out.println("Super");

    }

}

 

class Derived extends Super {

    public Derived() {

    }

    public void test() {

        System.out.println("Derived");

    }

}

 

    当然,学语言没有必要务求表达精确。这是个“度”的问题了。

  • 大小: 7 KB
  • 大小: 5.5 KB
  • 大小: 5.3 KB
分享到:
评论
7 楼 ZangXT 2009-09-13  
凤舞凰扬 写道
   所以在java的早期版本中使用private final来表达,从而提升性能。而在java2后,private默认也就是final的了,不需要在加上final的描述,如果接口方法不需要再加上public abstract的描述一样。如果楼主用SUN也推荐的findbox,你就可以看到相关的警告描述。

static方法也可以内联优化,显然static的无法添加final限定,因为添加了就改变了程序的语义。所以从内联角度无法说明这个问题。可以参考上面原文的修改。

findbox是不是findbug的笔误?
6 楼 jiyanliang 2009-09-11  
狂奔蜗牛 写道
读理科的?我看文也写的不错呀,你经常看鲁迅的作品吧!

你看错了吧,我说的是物理。当时c盛行。况且我也没有贬低他的意思,我只是实话实说罢了。。
5 楼 ZangXT 2009-09-11  
的字节码中又是否会有
凤舞凰扬 写道
   首先要给楼主说明一下情况,Java生成的字节码自然是按照代码本身的定义来进行的(比如private方法没有定义final,也就不会有对应的字节码产生,这丝毫不代表private是final的,如果楼主有兴趣,看看接口方法生产的字节码中又是否会有ACC_PUBLIC何ACC_ABSTRACT这样的信息呢)。其实这个区别是来自于c++中内联函数(inline)的概念,而在java中没有这样的概念,所以在java的早期版本中使用private final来表达,从而提升性能。而在java2后,private默认也就是final的了,不需要在加上final的描述,如果接口方法不需要再加上public abstract的描述一样。如果楼主用SUN也推荐的findbox,你就可以看到相关的警告描述。
 
引用
而且在这个层次上,内存的划分是由jvm规范定义的,包括pc寄存器、虚拟机栈、堆、方法区、常量池、本地方法栈等。好像书里还提到过静态存储区的概念,这个jvm里也是不存在的。
我如果没有理解错的话,这里说的静态存储区应该就是permgen,因为在前面的语句中刚好就漏了它。所以楼主说它不存在,要看你怎么理解这个翻译了。

   至于后面的,晦涩,没看懂,不发表意见

接口的方法是有ACC_PUBLIC和ACC_ABSTRACT标记的。所以这个比较类比不能成立。

如果从“语义”的角度将,认为private的方法有类似final的功能,这个我是赞同的。如果从语言角度这么提,我认为是毫无道理的。从方法绑定的角度看,invokespecial调用private方法时,可以根据引用的类型绑定方法。所谓的“final“语义,似乎就是指这一点了。

在SUN的jvm里,所谓的“静态数据区”应该是对应PermGen的,或者是PermGen的一部分。这跟翻译无关,只是我不喜欢书里的表达而已。

findbox我没看过,谢谢提示。
4 楼 凤舞凰扬 2009-09-10  
   首先要给楼主说明一下情况,Java生成的字节码自然是按照代码本身的定义来进行的(比如private方法没有定义final,也就不会有对应的字节码产生,这丝毫不代表private是final的,如果楼主有兴趣,看看接口方法生产的字节码中又是否会有ACC_PUBLIC何ACC_ABSTRACT这样的信息呢)。其实这个区别是来自于c++中内联函数(inline)的概念,而在java中没有这样的概念,所以在java的早期版本中使用private final来表达,从而提升性能。而在java2后,private默认也就是final的了,不需要在加上final的描述,如果接口方法不需要再加上public abstract的描述一样。如果楼主用SUN也推荐的findbox,你就可以看到相关的警告描述。
 
引用
而且在这个层次上,内存的划分是由jvm规范定义的,包括pc寄存器、虚拟机栈、堆、方法区、常量池、本地方法栈等。好像书里还提到过静态存储区的概念,这个jvm里也是不存在的。
我如果没有理解错的话,这里说的静态存储区应该就是permgen,因为在前面的语句中刚好就漏了它。所以楼主说它不存在,要看你怎么理解这个翻译了。

   至于后面的,晦涩,没看懂,不发表意见
3 楼 狂奔蜗牛 2009-09-09  
读理科的?我看文也写的不错呀,你经常看鲁迅的作品吧!
2 楼 ZangXT 2009-09-05  
jiyanliang 写道
Bruce Eckel本科是读物里的,后来才转过来读软件工程,可以说是半路出家吧

很多读物理然后去搞计算机的,特别猛。Bruce Eckel应该是C++标准委员会的成员。
1 楼 jiyanliang 2009-09-05  
Bruce Eckel本科是读物里的,后来才转过来读软件工程,可以说是半路出家吧

相关推荐

    深度强化学习:DDPG、TD3、SAC与机器人MuJoCo

    内容概要:本文详细介绍了三种主流的深度强化学习算法-DDPG、TD3和SAC在机器人控制领域的应用,特别是在MuJoCo仿真环境中的实现细节。首先解释了每个算法的基本原理及其独特之处,如DDPG的确定性策略生成器、TD3的双Critic网络以及SAC的熵最大化机制。接着深入探讨了这些算法的具体代码实现,包括Actor和Critic网络的设计、损失函数的构建以及一些实用的调参技巧。此外,还分享了许多实战经验和常见陷阱,如正确处理done信号、添加动作变化量惩罚项、观测空间的归一化等。 适合人群:对深度强化学习有一定了解并希望深入了解其在机器人控制领域应用的研究人员和技术爱好者。 使用场景及目标:帮助读者掌握如何将DDPG、TD3和SAC应用于具体的机器人控制任务中,提高算法性能,解决实际问题。同时,也为进一步研究提供了宝贵的实践经验。 其他说明:文中不仅提供了详细的理论讲解,还附带了大量的代码片段,便于读者理解和实践。对于想要深入理解这些算法内部运作机制的人来说,是一份不可多得的学习资料。

    基于QEM的优化网格简化算法C和C++实现源码(含论文).zip

    【资源说明】 1.项目代码功能经验证ok,确保稳定可靠运行。欢迎下载使用!在使用过程中,如有问题或建议,请及时私信沟通。 2.主要针对各个计算机相关专业,包括计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网等领域的在校学生、专业教师或企业员工使用。 3.项目具有丰富的拓展空间,不仅可作为入门进阶,也可直接作为毕设、课程设计、大作业、初期项目立项演示等用途。 4.当然也鼓励大家基于此进行二次开发。 5.期待你能在项目中找到乐趣和灵感,也欢迎你的分享和反馈! 本文介绍了基于QEM(Quadric Error Metrics,二次误差度量)的优化网格简化算法的C和C++实现源码及其相关文档。这一算法主要应用于计算机图形学领域,用于优化三维模型的多边形数量,使之在保持原有模型特征的前提下实现简化。简化的目的是为了提高渲染速度,减少计算资源消耗,以及便于网络传输等。 本项目的核心是网格简化算法的实现,而QEM作为该算法的核心,是一种衡量简化误差的数学方法。通过计算每个顶点的二次误差矩阵来评估简化操作的误差,并以此来指导网格简化过程。QEM算法因其高效性和准确性在计算机图形学中广泛应用,尤其在实时渲染和三维打印领域。 项目代码包含C和C++两种语言版本,这意味着它可以在多种开发环境中运行,增加了其适用范围。对于计算机相关专业的学生、教师和行业从业者来说,这个项目提供了丰富的学习和实践机会。无论是作为学习编程的入门材料,还是作为深入研究计算机图形学的项目,该项目都具有实用价值。 此外,项目包含的论文文档为理解网格简化算法提供了理论基础。论文详细介绍了QEM算法的原理、实施步骤以及与其他算法的对比分析。这不仅有助于加深对算法的理解,也为那些希望将算法应用于自己研究领域的人员提供了参考资料。 资源说明文档强调了项目的稳定性和可靠性,并鼓励用户在使用过程中提出问题或建议,以便不断地优化和完善项目。文档还提醒用户注意查看,以获取使用该项目的所有必要信息。 项目的文件名称列表中包含了加水印的论文文档、资源说明文件和实际的项目代码目录,后者位于名为Mesh-Simplification-master的目录下。用户可以将这些资源用于多种教学和研究目的,包括课程设计、毕业设计、项目立项演示等。 这个项目是一个宝贵的资源,它不仅提供了一个成熟的技术实现,而且为进一步的研究和学习提供了坚实的基础。它鼓励用户探索和扩展,以期在计算机图形学领域中取得更深入的研究成果。

    IEEE 6 bus节点系统仿真:Matlab/Simulink质量保证的自主搭建模型,电压稳定且与标准参数一致的可观测电压

    内容概要:本文详细介绍了如何使用Matlab/Simulink搭建IEEE 6节点电力系统仿真模型,确保电压稳定并与标准参数一致。主要内容涵盖节点与线路搭建、负载设置、电压稳定控制以及电压观测方法。文中强调了通过自动电压调节器(AVR)模块保持电压稳定,并通过电压测量模块实现电压观测。此外,还讨论了模型验证和优化技巧,如故障仿真、负荷模型设置和数据可视化。 适合人群:从事电力系统研究和技术开发的专业人士,尤其是有一定Matlab/Simulink基础的工程师和研究人员。 使用场景及目标:适用于电力系统仿真、电压稳定性分析、故障响应测试等应用场景。目标是帮助用户掌握电力系统建模的基本步骤和关键技术,提高仿真模型的可靠性和准确性。 其他说明:文中提供了详细的代码示例和配置指南,有助于读者快速理解和应用。同时,作者分享了许多实践经验,如参数设置、故障排除和性能优化,使模型更加贴近实际工程需求。

    少儿编程scratch项目源代码文件案例素材-掉箱子.zip

    少儿编程scratch项目源代码文件案例素材-掉箱子.zip

    Apk包名信息提取(支持图标)

    Apk包名信息提取(支持图标)

    少儿编程scratch项目源代码文件案例素材-回放.zip

    少儿编程scratch项目源代码文件案例素材-回放.zip

    基于改进粒子群算法的混合储能系统容量优化程序

    内容概要:本文详细介绍了利用改进粒子群算法(PSO)进行混合储能系统(如电池与超级电容组合)容量优化的方法。文中首先指出了传统PSO易陷入局部最优的问题,并提出通过非线性衰减惯性权重、引入混沌因子和突变操作等方法来改进算法性能。随后,作者展示了具体的Python代码实现,包括粒子更新策略、适应度函数设计以及边界处理等方面的内容。适应度函数不仅考虑了设备的成本,还加入了对设备寿命和功率调节失败率的考量,确保优化结果的实际可行性。实验结果显示,在风光发电系统的应用场景中,改进后的PSO能够在较短时间内找到接近全局最优解的储能配置方案,相比传统方法降低了系统总成本并提高了循环寿命。 适合人群:从事电力系统、新能源技术研究的专业人士,尤其是对储能系统优化感兴趣的科研工作者和技术开发者。 使用场景及目标:适用于需要对混合储能系统进行容量优化的场合,旨在提高储能系统的经济效益和使用寿命,同时保证供电稳定性。通过学习本文提供的理论知识和代码实例,读者能够掌握改进粒子群算法的应用技巧,从而应用于实际工程项目中。 其他说明:文中提到的所有代码均为Python实现,且已在GitHub上提供完整的源代码链接(尽管文中给出的是虚拟地址)。此外,作者还计划将改进的PSO与其他优化算法相结合,进一步提升求解复杂问题的能力。

    2025 长城杯 决赛 二进制 附件 第二届 长城杯 国赛 二进制 附件

    2025 长城杯 决赛 二进制 附件 第二届 长城杯 国赛 二进制 附件

    【实例分享】详解MATLAB实现K均值聚类算法,基于样本数据进行聚类分析

    内容概要:本文详细介绍了K均值聚类算法的基本原理及其在Matlab中的具体实现。首先通过生成随机样本数据进行演示,展示了如何利用Matlab编写K均值聚类的核心代码,包括初始化质心、分配样本以及更新质心的关键步骤。文中还特别强调了距离计算部分使用的向量化操作,提高了程序运行效率。此外,提供了完整的代码示例,涵盖从数据准备到结果可视化的全过程,并讨论了一些常见的问题及解决方案,如初始质心的选择、异常值的影响等。 适合人群:对机器学习感兴趣的学生、研究人员和技术爱好者,尤其是希望深入理解K均值聚类算法内部机制的人士。 使用场景及目标:适用于初学者学习无监督学习的基础算法之一——K均值聚类,帮助他们掌握如何手动实现这一重要算法,同时能够将理论知识应用于实际数据分析任务中。对于想要进一步探索高级特性的用户,则可以参考提供的改进方向。 其他说明:文中提到的数据预处理(如标准化)、模型评估指标(如肘部法则)和潜在的问题(如局部最优解),都为后续研究提供了有价值的指导。

    单元测试革命:用mockall实现完美测试隔离.pdf

    文档支持目录章节跳转同时还支持阅读器左侧大纲显示和章节快速定位,文档内容完整、条理清晰。文档内所有文字、图表、函数、目录等元素均显示正常,无任何异常情况,敬请您放心查阅与使用。文档仅供学习参考,请勿用作商业用途。 Rust 以内存安全、零成本抽象和并发高效的特性,重塑编程体验。无需垃圾回收,却能通过所有权与借用检查机制杜绝空指针、数据竞争等隐患。从底层系统开发到 Web 服务构建,从物联网设备到高性能区块链,它凭借出色的性能和可靠性,成为开发者的全能利器。拥抱 Rust,解锁高效、安全编程新境界!

    语音转文字脚本,实现语音转文字

    可实现语音转文字

    少儿编程scratch项目源代码文件案例素材-功夫 第一关.zip

    少儿编程scratch项目源代码文件案例素材-功夫 第一关.zip

    少儿编程scratch项目源代码文件案例素材-光明与黑暗(1).zip

    少儿编程scratch项目源代码文件案例素材-光明与黑暗(1).zip

    少儿编程scratch项目源代码文件案例素材-多节奏(动画).zip

    少儿编程scratch项目源代码文件案例素材-多节奏(动画).zip

    少儿编程scratch项目源代码文件案例素材-洞穴生存.zip

    少儿编程scratch项目源代码文件案例素材-洞穴生存.zip

    基于UDS的Bootloader:源码与测试用例共享,支持Autosar与多种通信协议定制,包括CANfd,多个版本可选

    内容概要:本文详细介绍了基于UDS(Unified Diagnostic Services)协议的Bootloader的设计与实现,涵盖其多协议支持(XCP、CCP、UDS)、AUTOSAR兼容性、多版本选择(ILLD和MCAL)、广泛硬件平台支持(如TC系列芯片)以及CAN FD的支持。文中不仅提供了上位机和下位机的代码示例,还展示了具体的测试用例,确保Bootloader的功能正确性和稳定性。此外,文章探讨了Bootloader在汽车电子和工业控制系统中的应用场景,强调了其重要性和灵活性。 适合人群:从事汽车电子、嵌入式系统开发的技术人员,尤其是那些需要深入了解Bootloader工作机制和实现细节的人群。 使用场景及目标:适用于需要开发或维护汽车电子控制单元(ECU)的团队,旨在提高系统的可靠性和性能。目标包括但不限于:实现高效的数据传输、确保诊断服务的准确性、优化刷写速度、增强系统的安全性等。 其他说明:文章提供了丰富的代码示例和技术细节,帮助读者更好地理解和应用基于UDS的Bootloader。同时,针对不同硬件平台和应用场景,给出了具体的配置建议和注意事项。

    少儿编程scratch项目源代码文件案例素材-飞行狂热.zip

    少儿编程scratch项目源代码文件案例素材-飞行狂热.zip

    Socket TCP通信C# Winform控件封装,集成简单,服务端与客户端全涵盖,源码及应用案例一键下载

    内容概要:本文详细介绍了在C# Winform环境中实现Socket TCP通信的一种高效方式,即通过封装的服务端和客户端控件来简化开发流程。文中不仅讲解了控件的基本使用方法,如服务端监听、客户端连接、数据传输等核心功能,还探讨了控件内部的工作原理,包括异步通信、事件驱动机制以及线程安全管理等方面。此外,文章还提供了一些典型应用场景的具体实现,如聊天程序、文件传输等,帮助开发者更快地上手并解决实际问题。 适合人群:具有一定C#编程基础,希望快速掌握Socket TCP通信开发的程序员。 使用场景及目标:适用于需要在网络编程中快速搭建稳定可靠的通信系统的项目,旨在提升开发效率,降低开发难度,使开发者能够专注于业务逻辑而非底层通信细节。 其他说明:控件源码公开,便于进一步学习和定制化开发;附带多个应用案例源码,涵盖常见网络通信任务,有助于理解和实践。

    少儿编程scratch项目源代码文件案例素材-愤怒的小鸟躲避.zip

    少儿编程scratch项目源代码文件案例素材-愤怒的小鸟躲避.zip

    少儿编程scratch项目源代码文件案例素材-钢琴.zip

    少儿编程scratch项目源代码文件案例素材-钢琴.zip

Global site tag (gtag.js) - Google Analytics