`
ZangXT
  • 浏览: 118298 次
  • 性别: 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本科是读物里的,后来才转过来读软件工程,可以说是半路出家吧

相关推荐

    Java编程思想(完整版)

    ### Java编程思想(完整版) #### 第1章 对象入门 **1.1 抽象的进步** 抽象在软件工程中扮演着极其重要的角色。通过抽象,开发者能够关注于概念的本质特征,而忽略掉不必要的细节。这有助于降低系统的复杂度,使得...

    java编程思想读书笔记

    ### Java编程思想读书笔记 #### 一、Java与C++的区别及内存管理 在学习Java的过程中,我们常常会拿它与C++进行比较。这两门语言虽然有着相似之处,但也有许多不同点。 1. **内存管理:** - C++提供了更为底层的...

    java 编程思想.txt

    根据提供的文件信息,我们可以深入探讨《Java编程思想》这一主题中的关键知识点,这些知识点主要集中在类、对象、封装性、继承、多态等核心概念上。 ### Java编程思想概述 《Java编程思想》这本书深入浅出地介绍了...

    java编程思想书本示例和习题答案

    《Java编程思想》是 Bruce Eckel 的经典著作,这本书深入浅出地介绍了Java语言的核心概念和技术,被广大Java程序员视为学习Java的必备参考书。这个压缩包包含了书中的实例代码和习题答案,对于读者理解和掌握Java...

    Java编程思想重点笔记(Java开发必看)

    1. **动态绑定**:在Java中,除了`static`方法和`final`方法(包括`private`方法,因为它们不能被子类覆盖)之外,其他所有方法都是动态绑定。这意味着在运行时,系统会根据对象的实际类型来决定调用哪个方法。这种...

    JAVA面向对象编程思想

    ### JAVA面向对象编程思想 #### 一、面向对象的基本概念 面向对象编程(Object-Oriented Programming,简称OOP)是一种编程范式,它通过模拟现实世界中的对象及其交互方式来构建软件系统。Java作为一种典型的面向...

    深入解析Java编程中final关键字的作用

    在Java编程中,final关键字扮演着至关重要的角色,它用于声明不可变的变量、方法以及类,以确保代码的稳定性和安全性。以下是关于final关键字的深入解析: 1. **final类**: 当一个类被声明为final时,这意味着这...

    java编程思想 答案+源代码.rar

    《Java编程思想》是 Bruce Eckel 的经典著作,这本书深入浅出地讲解了Java语言的各个方面,对于初学者和有经验的程序员来说都是极好的学习资源。提供的"java编程思想 答案+源代码.rar"压缩包包含了本书的解答和源...

    java编程思想练习答案 the think in Java Annotated Solution Guide

    《Java编程思想》是 Bruce Eckel 的经典之作,它深入浅出地介绍了Java这门强大的编程语言。这本书的章节练习答案则是对书中理论知识的实践检验,帮助读者巩固理解并提升编程技能。以下是对这份"Java编程思想练习答案...

    Java编程思想第五章练习和习题

    《Java编程思想第五章练习与习题》章节涵盖了Java编程中的关键概念,这些概念对于深入理解和熟练运用Java语言至关重要。本章的练习旨在巩固和拓展读者在类、对象、继承、多态等核心主题上的理解。以下是根据描述和...

    java中final和static的区别

    4. 用 private 修饰的 static 成员变量和成员方法,表示这个变量可以在类的静态代码块中,或者类的其他静态成员方法中使用(当然也可以在非静态成员方法中使用),但是不能在其他类中通过类名来直接引用,这一点很...

    java 编程思想4(中文版pdf)

    《Java编程思想》是 Bruce Eckel 的经典著作,这本书深入浅出地讲解了Java语言的核心概念和编程技术,是Java程序员的重要参考书籍。中文版的出现使得更多的中国开发者能够无障碍地学习这本巨著,无需面对语言障碍。...

    Java编程思想_第4版—习题答案.rar

    而"Java编程思想_第4版—习题答案"这个压缩包则为读者提供了书中的习题解答,是学习过程中不可或缺的辅助资料。 1. 面向对象编程:Java是一种面向对象的语言,它强调将数据和操作数据的方法封装在一起,形成对象。...

    java编程思想thinking in java

    《Java编程思想》是 Bruce Eckel 的经典著作,它深入浅出地介绍了Java语言的核心概念和技术,对于初学者和有经验的程序员来说都是极好的学习资源。这本书从对象的概念出发,逐步引导读者深入理解Java的世界。 1. **...

    Java编程思想答案

    "Java编程思想答案"是针对这些练习题的解答,能够帮助读者检验自己的学习效果,解决学习过程中遇到的问题。 在学习Java编程时,掌握以下几个核心知识点至关重要: 1. **基础语法**:Java是一种静态类型的、面向...

    java 编程思想

    ### Java编程思想:为何面向对象编程在软件开发领域有如此深远的影响 #### 一、面向对象编程(OOP)的概念及重要性 面向对象编程(Object-Oriented Programming,简称OOP)是一种软件开发方法,它将数据和处理数据...

    Java编程思想全面的答案

    《Java编程思想全面的答案》这份资源集合了众多Java编程思想的学习习题解答,旨在帮助学习者深入理解并掌握Java编程的核心概念。以下是对这个主题的详细解析: Java编程思想是学习Java编程的基础,它涵盖了面向对象...

    Java编程思想重点笔记(Java开发必看).pdf

    Java编程思想是每个Java开发者必备的知识体系,涵盖了Java语言的核心概念和高级特性。这篇笔记将聚焦于Java中的多态性,这是面向对象编程的关键概念,同时也涉及到构造函数、静态方法和final关键字的理解。 1. **...

    Java编程思想面向对象逻辑思维方法

    在探讨“Java编程思想面向对象逻辑思维方法”这一主题时,我们深入剖析了面向对象编程(Object-Oriented Programming,OOP)的核心理念及其在Java中的应用方式。面向对象编程是一种编程范式,它将数据和操作数据的...

Global site tag (gtag.js) - Google Analytics