摘要
Java作为一种面向对象(Object Oriented)的编程语言,一切事物都可以看成对象,而Object是java一切Class的父类,也就是说,java中一切除Object的class都继承自Object,因此对Object类的理解对于学习java有着至关重要的意义。
从类方法看Object
java设计者将几乎所有的类都需要的高频使用的方法集成到一个超类中,这就是Object,Object中含有的方法如下:
public final native Class<?> getClass();
public native int hashCode();
public boolean equals(Object obj);
protected native Object clone();
public String toString();
public final native void notify();
public final native void notifyAll();
public final native void wait(long timeout);
public final void wait(long timeout, int nanos);
public final void wait();
protected void finalize();
getClass()
在Object类中,getClass()方法被关键字native修饰,表明其实现使用了JNI(java
native interface),本文对此不作深入了解。
此方法与java反射机制有关,可以得到类的详细信息(类名,类方法等),在之后涉及到class Class再详细解析。
hashCode()
从方法声明可以得知,hashCode()返回了一个int值,此int值便是调用此方法的实例的哈希值。对于含有容器类型的程序设计语言来说,哈希值至关重要。
在java中,这样的容器数据类型有HashMap,HashTable,HashSet。当插入一条记录时,如何保证插入的数据是否已经存在,如何快速找到需要的数据成为最重要的问题。三种数据类型中都有形如 <K,V>
的数据结构,在HashMap与HashTable中是Entry<K,V>[] table
,HashSet中则是HashMap<E,Object> map
,其中的K值便通常是类实例调用hashCode()方法产生的int值,称为散列值。
getClass中提到,native修饰的方法是本地方法,其实现与JVM的实现有关,hashCode()生的值同样与虚拟机有关,通常来说,与对象的存储地址有关。(有时间再补充)
虽然可以用hashCode来表示对象,但不能仅凭hashcode相同来证明两个对象是一致的。所以在散列表的设计中需要涉及到解决冲突算法。
equals
从Obejct中equals的实现
public boolean equals(Object obj) {
return (this == obj);
}
可以得知返回的是传入对象与当前对象引用地址是否一致,对于java基本类型(String,Integer等),都对equals()进行了重写,保证了比较引用地址的同时还比较存储的数值。所以一般编写自己的类时需要用到equals()时,应该重写方法,否则可能出错。
clone()
同样是本地方法,返回一个Object,顾名思义,这是一种克隆对象的方法,返回的是当前对象的克隆。
这里我们知道创建对象也可以使用clone()方法。我们知道操作符“=”同样可以将新对象指向同一对象引用
测试如下代码:
Apple app=new Apple();
app.setName("红苹果");
Apple app1=app;
Apple app2=app.clone();
System.out.println(app);
System.out.println(app1);
System.out.println(app2);
其中class Apple必须重写clone(),实现Cloneable接口。
输出如下:
Apple@610455d6
Apple@610455d6
Apple@511d50c0
可见操作符“=”仅仅将同一对象的引用指向新对象“app1”,堆区没有创建新对象,而clone()直接在堆区创建了新对象。
toString()
看Object中的实现
return getClass().getName() + "@" + Integer.toHexString(hashCode());
返回“类名@hashcode()值的16进制表示”,hashcode()的生成与地址有关,所以可以一定程度上反映当前对象再内存上的存储状态。
通常我们使用自己创建的类的toString方法时,会将需要了解的类的信息打印出来,而不仅仅是类名和hashcode。
wait()
此方法在Object中声明为final,无法重写,由JVM实现。是多线程编程中重要的方法。
有三个重载
public final native void wait(long timeout);
public final void wait(long timeout, int nanos);
public final void wait();
某对象调用wait()方法后,当前线程阻塞(此线程必须拥有该对象的monitor),释放锁,等待被唤醒。
1.wait()
:当前线程阻塞,直到被唤醒。
2.wait(long time)
:当前线程阻塞,直到其他线程调用此对象的 notify()
方法或 notifyAll()
或超过设定时间
3.wait(long timeout, int nanos)
:当前线程阻塞导致当前的线程等待,直到其他线程调用此对象的 notify()
方法或 notifyAll()
方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。
notify()
此方法在Object中声明为final,无法重写,由JVM实现。是多线程编程中重要的方法。
唤醒在此对象监视器上等待的单个线程。
notifyAll()
唤醒在此对象监视器上等待的所有线程。
finalize()
垃圾回收器准备释放内存的时候,会先调用finalize()。
小结
本文从Obejct的类方法初步分析了java编程中常用的方法用途及其实现,助于进一步理解Object。更多的细节没有详细阐述,日后会有进一步的更新。不足之处,多多指正!