想要深入学习JAVA,还需追本溯源,从源码学起。这是我目前的想法。如今JAVA各种开源框架涌出,很多JAVA程序员都只停留在如何熟练使用的层次。身为其中一员的我深感惭愧,所以要加快学习的脚步,开始研究源码。希望这个系列我可以坚持下去。
JAVA程序员都知道Object是所有类的父类,所以,今天就从Object开始记录我的源码之路。
网上有很多关于Object类的详解,这里我只总结一点我所学到的,算是做个记录吧。
首先要看Object.class中的几个方法:
private static native void registerNatives(); public native int hashCode(); public boolean equals(Object obj) { return (this == obj); } protected native Object clone() throws CloneNotSupportedException; public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } public final native void notify(); public final native void wait(long timeout) throws InterruptedException; protected void finalize() throws Throwable {}//空的方法
话说在这之前我还不知道native关键字是什么意思。下面是我的总结:
native
- native用来修饰方法(Method),表示是另外一种语言实现的本地方法。看上去更像是一个调用非JAVA语言写的方法的接口。【JNI(Java native interface):JAVA本机接口】
- native方法可以和除了abstract的任何JAVA方法修饰符一起使用,如static、synchronized等。【例Object类中的registerNatives(),不能与abstract一起使用的原因可以猜得到:native有实现】
- native方法的实现中可以访问JAVA特性,返回值也可以是一个JAVA类。【但是会很麻烦,
FindClass()获取类、
】GetMethodId()获取方法、CallVoidMethod()调用方法等等,但一般这么调用效率较低,可尽可能用字节数组。
- native方法可以被继承、可以抛异常等等。【与一个普通JAVA方法没什么两样。】
native方法存在的意义【只是我粗浅的理解】
JAVA语言是不能实现对操作系统底层的控制,这是为了让JAVA可以跨平台【不同的操作系统实现方式是不同的嘛】。这时候就要借助其它语言实现后,就可以通过JNI调用,就是这些native方法。其实这也就是JAVA跨平台的原理:使用其它语言【C\C++】针对不同操作系统写出不同的代码而实现同样的功能【如对内存、I/O的访问】,例如Object类中的notify()
、wait(long timeout),对于不同的操作系统调用不同的C语言的实现代码。
网上找的native方法的用处:
- 与旧有代码集成,避免重新编写。
- 实现可用类库中所缺少的功能。举例来说,在 Java 语言中实现
ping
时,您可能需要 Internet Control Message Protocol (ICMP) 功能,但基本类库并未提供它。- 最好与使用 C/C++ 编写的代码集成,以充分发掘性能或其他与环境相关的系统特性。
- 解决需要非 Java 代码的特殊情况。举例来说,核心类库的实现可能需要跨包调用或者需要绕过其他 Java 安全性检查。
native方法的简单实现
基本有如下步骤,我自己没实现过,只是用于大致了解和记忆:
- 在JAVA中声明native Method;
- 用javah命令产生一个.h文件;
- 用C语言(C++)写.c文件(.cpp),其中要#include "CheckFile.h"和#include "jni.h"【虽然我没有看过jni.h,但猜测是声明或实现了
FindClass()
这种可以与JAVA交互的方法】; - 将.c\.cpp文件生成.dll文件(动态链接库文件)。
- 在JAVA中用System.loadLibrary()方法加载.dll文件,这个native方法就可以在JAVA中被访问了。
关于native就到此为止,这有一篇关于JNI的文章:http://www.ibm.com/developerworks/cn/java/j-jni/
Object类中还有一些其它方法,如hashCode()和equals()这对组合。hash是一种程序员必须有的思想,具体会在后面HashMap的学习中详细记录,这里只写JDK的API上的解释:
- equals 方法体很简单,return (this == obj); 可以简单的理解为地址相同,下面是来自API的描述:
equals
方法在非空对象引用上实现相等关系:
- 自反性:对于任何非空引用值
x
,x.equals(x)
都应返回true
。- 对称性:对于任何非空引用值
x
和y
,当且仅当y.equals(x)
返回true
时,x.equals(y)
才应返回true
。- 传递性:对于任何非空引用值
x
、y
和z
,如果x.equals(y)
返回true
,并且y.equals(z)
返回true
,那么x.equals(z)
应返回true
。- 一致性:对于任何非空引用值
x
和y
,多次调用 x.equals(y) 始终返回true
或始终返回false
,前提是对象上equals
比较中所用的信息没有被修改。- 对于任何非空引用值
x
,x.equals(null)
都应返回false
。
Object
类的 equals 方法实现对象上差别可能性最大的相等关系;即,对于任何非空引用值x
和y
,当且仅当x
和y
引用同一个对象时,此方法才返回true
(x == y
具有值true
)。注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
- hashCode 可以简单的认为返回的是对象的地址,但实际是经过一个算法处理成一个整数的。
hashCode
的常规协定是:
- 在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
- 如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用
hashCode
方法都必须生成相同的整数结果。- 如果根据
equals(java.lang.Object)
方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不 要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。
剩下的方法这里就不再赘述了,因为回到文章的主题是想学习源码,而java.lang.Object类实际并没有什么源码【都是native方法用其它语言实现的】,所以诸如clone()的浅拷贝、深拷贝,以及多线程相关等等一开始学JAVA的时候都学过的,都留给平时去应用吧。
好了,关于源码的第一篇文章就到这里吧,还是开始提到的,希望我可以将这个系列坚持下去。