java源码学习-详解Object类
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java源码学习-详解Object类相关的知识,希望对你有一定的参考价值。
java语言的学习,研究JDK源码是掌握基本语法之后,提升能力的一个很重要的途径。
本篇内容主要解决以下内容:
1)对Object中的方法进行一个简单的总结;
2)对每个方法进行解读,主要包括注意事项和开发中需要注意的点;
3)简单描述一下Object中这几个方法的作用与java语言中那些特性相关;
/*
Object类是java类层次体系的根类,也就是所有类的父类。所有的类,包括数组,都实现了Object类中的方法。
类的权限修饰符也很重要啊,看清权限修饰符
*/
public class Object { }
/*
registerNatives(),是Object类私有的,主要将本地方法注册到虚拟机中
*/
private static native void registerNatives(); static { registerNatives(); }
/*
public:表示方法是公有的,final修饰,表示每个类得到的字节码对象的地址引用,在内存中的位置是固定的,native修饰,具体实现是有虚拟机来实现
*/
public final native Class<?> getClass();
/*
功能:返回当前对象的hash值
目的:为java中散列表提供服务
注意事项:
1) 在一个java应用的运行期间,同一个对象多次调用这个方法,应该返回同一个整数。
2) 对同一个对象来说,第一次运行这个程序得到的hashcode值和第二次运行这个程序得到的hashcode值可以不一样
3) 如果两个对象通过equals(Object)方法判断的结果为true,那么这两个对象调用各自的hashcode方法应该返回相同的整数值
4) 两个对象通过equals方法返回的结果为false,那么他们各自的hashcode方法的返回值,可以相同,(也可以不相同)。但是作为程序设计员应该意识到两个对象通过equals方法返回的结果应该与hashcode方法的返回值的比较结果一致,
这样会提高哈希表的性能。这也就是为什么说在重写equals方法的时候,需要重写hashcode方法的缘由。
*/
public native int hashCode();
/*
功能:用来表明这个对象和其他的对象是否是相等的。
特性:
1 自反性 一个对象应该和自己是相等的
2 对称性 对于两个非空引用,x,y; x.equals(y)的结果和y.equals(x)一致
3 传递性 对于任意一个非空引用 x,y,z x.equals(y) == true x.equals(z) == true,则y.equals(z) == true
4 一致性
5 唯一性 对于任何非空引用x,x.equals(null) === false
注意事项:
1 在没有重写equals方法的时候,对于任意两个非空引用x,y若x.equals(y)则意味着它们指向相同的地址引用
2 当equals方法被重写的时候,hashcode方法也是需要被重写的,目的就是维护一个契约,equals方法的结果和hashcode方法的结果一致
*/
public boolean equals(Object obj) { return (this == obj); }
/*
权限修饰符:protected,这个很重要,意思也很简单的只有类自己的对象才可以调用这个方法,保证了安全,维护了秩序。
异常 :CloneNotSupportedException,对象调用clone()方法,必需要实现Cloneable接口(Object类没有实现这个接口 Object obj = new Object(); obj对象没有clone()方法的),否则在运行时抛出此异常
功能 :创建并返回当前对象的一个副本。 这个副本和原对象并不总是一致的,也就是这是一个浅拷贝(与深度拷贝的详细将在另一篇文章中详细介绍,并给出具体的实现)。具体分析如下:
1、对于一个非空对象 x.clone() != x,x和x.clone()具有不同的内存地址
2、x.clone().getClass() == x.getClass()为true
3、数组类型的接口都实现了Cloneable接口,同时如果数组类型的装载的是基本数据类型(int,double,String等),则使用该方法,在新clone的对象中,该值是存在的
*/
protected native Object clone() throws CloneNotSupportedException;
/*
功能:返回当前对象的一个字符串表示形式。
getClass().getName()获取当前的字节码对象后再获取当前的对象的包名+类名
返回结果:当前对象的包名+类名+"@"+当前对象的hashcode值的16进制的表示形式
推荐:对所有需要描述类信息的对象重写该方法,因为这样的形式不利于直观的描述对象的信息
*/
public String toString() { return getClass().getName() + "@" Integer.toHexString(hashCode()); }
/*
功能:唤醒一个正在等待此对象监视器的单线程
注意事项:
1)如果有多个线程均在等待这个对象,那么只有一个线程可以被唤醒,被唤醒的线程是随机的。
2)通过调用wait方法,实现一个线程对一个对象监视器的等待
3)只有当前线程放弃当前对象的锁,那么被唤醒的线程才可以执行。但是唤醒的线程并没有特权或者劣势去得到下一个该对象的锁(随机的)
4)在同一时间,只有一个线程可以得到这个对象监视器
方法调用:
1)这个线程对象监视器的主人可以调用这个方法。
一个线程拥有这个对象监视器一般有三种方法:
1 实例方法上
2 方法内代码块(实例方法和静态方法,实例方法内可以是任意对象,静态方法只能是当前类的字节码文件对象)
3 静态方法上
*/
public final native void notify();
对象监视器的三种方法:
1 public class ObjectStudy { 2 3 private Object lock = new Object(); 4 5 /** 6 * 语句的主体在当前类对象上同步 7 */ 8 public synchronized void test() { 9 System.out.println("hello test1 ..."); 10 } 11 12 /** 13 * 通过任意对象来进行同步,可以使用this 14 */ 15 public void test2() { 16 System.out.println("hello world"); 17 synchronized (lock) { 18 System.out.println("hello test2 ..."); 19 } 20 } 21 22 /** 23 * 类的同步静态方法 24 */ 25 public synchronized static void test3() { 26 System.out.println("hello test3 ..."); 27 } 28 public static void test4() { 29 synchronized(new ObjectStudy().getClass()){ 30 System.out.println("hello test3 ..."); 31 } 32 } 33 }
/*
功能:唤醒所有正在等待此对象的监视器
注意事项:
1 虽然所有线程都被唤醒,但在同一时间只有一个线程可以执行
方法调用参见notify()方法
*/
public final native void notifyAll();
/*
功能:使当前线程处于等待状态,直到另一线程调用notify方法或者notifyAll()方法,又或者超过指定时间,该线程开始执行
*/
public final native void wait(long timeout) throws InterruptedException;
/*
功能:使线程处于等待状态
参数:
long timeout -->等待的最大时间,单位是毫秒
int nanos -->附加时间,提高精确度,取值范围在0-999999
异常:
参数不合格会抛出运行时异常
*/
public final void wait(long timeout, int nanos) throws InterruptedException { if (timeout < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (nanos < 0 || nanos > 999999) { throw new IllegalArgumentException( "nanosecond timeout value out of range"); } // 对timeout取一个合理的值
if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {
timeout++;
}
wait(timeout);
}
/*
*/
public final void wait() throws InterruptedException { wait(0); }
/*
功能:当垃圾收集器认为该对象的引用没有被在任何被引用时,垃圾收集器会调用此方法进行垃圾回收。
修饰符:protected --> 子类可以重写该方法,去处理系统资源,并进行其他一些清理操作。
*/
protected void finalize() throws Throwable { }
总结:
本地方法7个:
private static native void registerNatives()
public final native Class<?> getClass()
public native int hashCode()
protected native Object clone()
public final void notify()
public final native void notifyAll()
public final native void wait(long timeout)
非本地方法5个:
public boolean equals(Object obj)
public String toString()
public final void wait(long timeout,int nanos)
public final void wait()
protected void finalize()
静态代码块:
static {
registerNatives();
}
一、体会权限修饰符使用的魅力,private,public,protected,除了包级默认的修饰符,Object类中全包含了;现在简要的分析一下:
1) private static native void registerNatives(),这个方法只有Object类自己调用,在Object类加载的时候执行,主要对几个本地方法进行注册(可以理解为将本地方法映射到虚拟机中)
2) public final native Class<?> getClass(),注意方法前的final修饰符,表明这个方法是由虚拟机来实现的,子类不能够重写
3) public native int hashCode(),这也是一个本地方法,但是却允许子类对其重写
4) protected native Object clone(),这个方法的权限修饰符是protected,是public又会怎么样呢?
a)对protected关键字进行一下解读,在同一个包下,该类的对象可以访问到protected修饰的方法,该类的子类可以在任何情况下访问到父类的protected修饰的方法
b)如果一个类没有重写clone()方法,那么只有创建在该类中的类的对象才可以访问到clone()方法,因为此时访问的是Object类的clone()方法,此时对clone()方法的访问是基于子父类的关系访问到的,在这种情况下,如果在其他的类中访问clone()方法,
是无法访问的,因为Object和当前类不在同一个包下。
c)这个权限修饰符只能是protected,原因是保证clone()方法的可控性
d)建议子类在对Object类中clone()方法进行重写时,权限修饰符仍为protected,除非你可以保证一切尽在掌控之中。
5) protected void finalize(),修饰符是protected,可以参考 4)
二、对方法功能进行简要概述
1 registerNatives() 私有方法,注册本地方法
2 getClass(),获取字节码对象,与java中反射机制有关
3 hashCode(),为java中哈希数据结构提供支持
4 toString(),对对象进行描述
5 clone(),提供对象克隆
6 notify、notifyAll、wait方法和java中的线程有关
7 finalize,与垃圾回收相关
8 equals(),用于判断两个对象是否相等
三、关于Object类的思考
1、权限修饰符的使用,在写程序的时候,认真思考一下,使用什么的样的权限修饰符,你是否真的搞明白了权限修饰符的用法?
2、final、native关键字的理解,当然还有构造方法、静态代码块,构造代码块,静态方法,静态成员变量的执行顺序是怎样的?因为我们看到Object类中有静态代码块,看到了就思考一下。
3、这有一个很有趣的问题,notify、notifyAll、wait方法这些和多线程有关的类,为什么设置在Object类中?关于这几个方法的详细解读,将在介绍多线程时,进行描述。
4、关于一个常见问题的答案,重写equals()方法,为什么要重写hashcode()方法,可以JDK源码中找到合适的答案(在上文中已经描述的很清楚了)。
5、在学习的过程中,一定要对概念有深刻的理解概念,不能人云亦云。
四、小结
以上内容来自于JDK源码和自己的一些看法,如有不足或者错误的地方,还请大家多多指教,共同进步。本文内容纯属原创,转载请注明出处,谢谢!
以上是关于java源码学习-详解Object类的主要内容,如果未能解决你的问题,请参考以下文章