java.lang解析Object类

Object类:

<strong>public class Object</strong>

Object 是类层次结构的根类。每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。

构造方法摘要
Object()
           

 

方法摘要
protected  Objectclone()
          创建并返回此对象的一个副本。
 booleanequals(Object obj)
          指示其他某个对象是否与此对象“相等”。
protected  voidfinalize()
          当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
 Class<?>getClass()
          返回此 Object 的运行时类。
 inthashCode()
          返回该对象的哈希码值。
 voidnotify()
          唤醒在此对象监视器上等待的单个线程。
 voidnotifyAll()
          唤醒在此对象监视器上等待的所有线程。
 StringtoString()
          返回该对象的字符串表示。
 voidwait()
          在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
 voidwait(long timeout)
          在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。
 voidwait(long timeout, int nanos)
          在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。

由于Object类当中使用的native方法比较多,源码代码确实没有看到太多,下面参考Object.class来看下实现的方法:

首先我们定义一个CObject继承Object:

public class CObject extends Object


创建一个空的构造方法:

	/**
	 * 构造方法
	 */
	public CObject(){
		
	}	

下面是参照Object.class的源码来实现的:
clone方法:

 /**
  * 创建并返回此对象的一个副本
  * Object,212行
  */
 @Override
    protected native Object clone() throws CloneNotSupportedException;


由于是native的方法,没有看到太多的实现方法。

equals方法:

	/**
	 * 指示其他某个对象是否与此对象“相等”
	 * Object,148行
	 */
	@Override
	public boolean equals(Object obj) {
		// TODO Auto-generated method stub
		  return (this == obj);
	}


finalize方法:

	/**
	 * 当垃圾回收器确定不存在该对象的更多引用时,由对象的垃圾回收器调用此方法
	 * Object,555行
	 */
	@Override
    protected void finalize() throws Throwable { }

getClass方法:

	/**
	 * 返回此Object的运行时类
	 * 由于是final类型类,不能实现复写,由于是native的类,并不能看到源码,方法定义如下
	 * Object,63行
	 */
    //public final native Class<?> getClass();

hashCode方法:

     /**
      * 返回该对象的哈希码值,也是natvie方法
      * Object,100行
      */
   public native int hashCode();

notify和notifyAll方法:

	  /**
	   * 唤醒在此对象监视器上等待的单个线程
	   * 由于是native final方法,无法复写
	   * Object,271行
	   */
	  //public final native void notify();
	
	  /**
	   * 唤醒在此对象监视器上等待的所有线程
	   * 由于是native final方法,无法复写
	   * Object,295行
	   */
	  //public final native void notifyAll();

toString方法:

	  /**
	   * 返回该对象的字符串表示
	   * Object,235行
	   */
	  @Override
	    public String toString() {
	        return getClass().getName() + "@" + Integer.toHexString(hashCode());
	    }

wait方法:

	  /**
	   * 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
	   * Object,501行
	   */
//	    public final void wait() throws InterruptedException {
//	        wait(0);
//	    }
	  
	  /**
	   * 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。
	   * Object,382行
	   */
//	  public final native void wait(long timeout) throws InterruptedException;

	  
	  
	  /**
	   *  在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。
	   *  Object,446行
	   */
//	    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");
//	        }
//
//	        if (nanos > 0) {
//	            timeout++;
//	        }
//
//	        wait(timeout);
//	    }


这边所有的方法都没有什么好说的,实现的代码不多,有机会的话把native里面的实现也看一下,下面测试代码:

为了区别不同的对象是不同的,我们在CObject当中再添加两个方法:

	  public String name = "cObject";
	  
	  /**
	   * 自定义方法,获取一个名字区别不同的对象
	   * @return
	   */
	  public String getName(){
		  return name;
	  }
	  
	  /**
	   * 自定义方法,设置一个名字区别不同的对象
	   * @param name
	   */
	  public void setName(String name){
		  this.name = name;
	  }

测试clone和equals方法:

clone由于是protect的,并不能直接实现,后面放在cloneable接口或segment类当中来进行详细解释。

由于要使用到clone方法,必须要实现cloneable接口,否则会报出CloneNotSupportedException的错误:

public class CObject extends Object implements Cloneable{

下面是测试代码:

	/**
	 * 测试equals
	 * @param cObject
	 */
	public static void testEquals(CObject cObject){
		CObject newObject = cObject;
		
		//判断两个Object是否相等
		isEqual(cObject, newObject);
		
		
		Object o = null;
	try {
		//创建cObject的一个副本
		 o  =	cObject.clone();
	} catch (CloneNotSupportedException e) {

		e.printStackTrace();
	}
	
		//将副本的类型转换成CObject
		newObject = (CObject)o;
		
		//判断两个Object是否相等
		isEqual(cObject,newObject);
		
		System.out.println("newObect里面的名字为:" +newObject.name);
		
	}


结果为:

等于true的时候是我们直接把cObject的值直接赋值给的newObject,所以相等。

等于false时,我们是用clone方法复制了一个cObject的副本,然后赋值给newObject,所以不相等;我们最初给cObject里面赋值了一个name为cObject,所以,在newObject里面的name也为cObject,证明clone方法是复制了一个cObject的副本的。


测试finalize方法:

测试结果是使用和没有使用finalize方法都没有任何的结果,对象依然存在,资源并没有被释放掉,原因是Object里面的方法是这样定义的:

/**
	 * 当垃圾回收器确定不存在该对象的更多引用时,由对象的垃圾回收器调用此方法
	 * Object,555行
	 */
	@Override
    protected void finalize() throws Throwable { }
finalize方法里面并没有实现任何的内容,只是定义了一个protected方法,而且因为是受保护的方法,并不能在其他的包内实现它。
finalize方法的官方解释是:
当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。子类重写 finalize 方法,以配置系统资源或执行其他清除。

finalize 的常规协定是:当 JavaTM 虚拟机已确定尚未终止的任何线程无法再通过任何方法访问此对象时,将调用此方法,除非由于准备终止的其他某个对象或类的终结操作执行了某个操作。finalize 方法可以采取任何操作,其中包括再次使此对象对其他线程可用;不过,finalize 的主要目的是在不可撤消地丢弃对象之前执行清除操作。例如,表示输入/输出连接的对象的 finalize 方法可执行显式 I/O 事务,以便在永久丢弃对象之前中断连接。

Object 类的 finalize 方法执行非特殊性操作;它仅执行一些常规返回。Object 的子类可以重写此定义。

Java 编程语言不保证哪个线程将调用某个给定对象的 finalize 方法。但可以保证在调用 finalize 时,调用 finalize 的线程将不会持有任何用户可见的同步锁定。如果 finalize 方法抛出未捕获的异常,那么该异常将被忽略,并且该对象的终结操作将终止。

在启用某个对象的 finalize 方法后,将不会执行进一步操作,直到 Java 虚拟机再次确定尚未终止的任何线程无法再通过任何方法访问此对象,其中包括由准备终止的其他对象或类执行的可能操作,在执行该操作时,对象可能被丢弃。

对于任何给定对象,Java 虚拟机最多只调用一次 finalize 方法。

finalize 方法抛出的任何异常都会导致此对象的终结操作停止,但可以通过其他方法忽略它。

也就是说,finalize当中应该是需要自己实现具体回收的内容,这个方法只是JVM在GC前会调用这个方法而已。

测试hashCode、toString和getClass方法:

	/**
	 * 测试hashCode和toString方法
	 * @param cObject
	 */
	private static void testHashCode(CObject cObject){
		System.out.println(String.format("hashCode为%d,toString为:%s", cObject.hashCode(),cObject.toString()));
	}

结果为:

因为toString方法是这样实现的:

	        return getClass().getName() + "@" + Integer.toHexString(hashCode());
所以getClass获取的路径就是oathchen.lang.cls.CObject,toHexString方法放在Integer类里面来说。

测试wait和notify方法:

	/**
	 * 测试wait和notify方法
	 * @param cObject
	 */
	private  void testWaitAndNotify(CObject cObject){
		final CObject synObj = cObject;		
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				synchronized(synObj) {
					System.out.println("T1获取synObj的对象监视器,开始执行同步块");
					try {
						System.out.println("T1在 wait()时挂起了");
						synObj.wait();
						System.out.println("T1被T2唤醒后并重新获得synObj的对象监视器,继续执行");						
					}catch(InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println("T1获取synObj的对象监视器,结束同步块");
				}				
			};
		});
		t1.start();


		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("T2启动,但是因为T1占用了synObj的对象监视器,则等待T1执行synObj.wait来释放它");
				synchronized(synObj) {
					try {
						System.out.println("在T1执行synObj.wait后,T2获取synObj的对象监视器,进入同步块");
						synObj.notify();
						System.out.println("T2执行synObj.notify(),T1被唤醒,但T2还在同步块中,没有释放synObj的对象监视器,T1等待synObj的对象监视器");
//						TimeUnit.MINUTES.sleep(1);
						System.out.println("T2结束同步块,释放synObj的对象监视器,T1获取到synObj的对象监视器,并执行wait后面的操作");
					}catch(Exception e) {
						e.printStackTrace();
					}
				}				
			};
		});
		t2.start();
		
	}


结果为:


这段代码是借鉴http://xiemingmei.iteye.com/blog/1073940上面的内容,我自己也试着写了一个,发现效果不是很好,就用了这个,解释的比较清楚。我跟上面代码写的不一样的地方是我是直接extends Thread而且是通过构造方法传递的CObect参数进入Thread里面的,出了一些问题:

	//自定义一个线程
	class MyThread extends Thread{
		
		//一个线程当中有一个CObject数据
		CObject cObject = new CObject();//此处必须要new一个初始化,否则会报出空指针,虽然该变量已在main里面初始化过了
		
		//计数
		int count;
		
		//获取当前的计数
		public int getCount(){
			return count;
		}
		
		//初始化方法
		public MyThread(CObject cObject){
			cObject = this.cObject;
		}
		
		//复写run方法
		@Override
		public void run() {

			synchronized(cObject){
					for(int i=0;i<10;i++){
				//			先睡眠一秒
				try {
				sleep(1000);
				} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				}
			
						//使用hashCode判断不同的线程
				System.out.println(this.hashCode() +":"+ count++);
			
			
						if(count == 5){
				try {
					
					System.out.println("i am waiting");
					cObject.wait();
					
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		
						}
			}
		
		}
	}

相当于在这个Thread里面我定义了一个局部变量cObject,并没有初始化,而我同步的是局部变量的cObject,编译器应该是这样判断出空指针异常的,虽然我通过构造方法传递进来的值是初始化过的。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: java.lang.ObjectJava中所有的父,它定义了一些通用的方法,例如toString()和equals()。如果出现“无法解析java.lang.Object”的错误,可能是因为代码中使用了不正确的语法或缺少了必要的依赖库。建议检查代码中是否有拼写错误或语法错误,并确保所有必要的依赖库已正确导入。 ### 回答2: "无法解析java.lang.Object"是指在Java程序中遇到了无法解析java.lang.Object的错误。 java.lang.ObjectJava中所有的基,它包含了所有共有的方法和属性。当无法解析java.lang.Object时,意味着JDK(Java Development Kit)中的核心库没有被正确加载。 解决此问题的方法有以下几种: 1. 检查JDK安装:首先,确保已正确安装了JDK。可以在命令行中运行`java -version`命令,查看是否能正确输出JDK的版本信息。如果没有输出或输出异常,说明JDK没有安装或安装错误,需要重新安装。 2. 检查classpath设置:在Java程序中,classpath是指用于指定Java和资源文件的搜索路径的系统环境变量。请确保classpath正确设置,以便能够找到java.lang.Object。可以通过命令行运行`echo %classpath%`(Windows)或`echo $CLASSPATH`(Linux/Mac)命令来查看classpath设置。 3. 检查IDE或编译器配置:如果使用集成开发环境(IDE)或其他编译器进行Java开发,需要检查其配置是否正确。确保项目的构建路径或编译选项中包含了JDK的路径,并且没有错误配置导致无法解析java.lang.Object。 4. 检查Java项目依赖:如果使用了第三方库或框架,在编译和运行时需要确保相关的依赖库已正确引入,并且版本兼容。如果依赖的库中存在与java.lang.Object冲突的或版本不匹配的情况,可能会导致无法解析java.lang.Object。 总之,在遇到无法解析java.lang.Object的错误时,需要仔细检查JDK的安装、classpath设置、IDE或编译器配置以及项目依赖等环节,确保其正确性和一致性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值