Object类在java.lang包里面,是所有类的根,其他所有类的超类,所有对象都实现了Object的方法。Object类有1个构造方法和11个方法:
public class Object {
public Object() {
}
public final native Class> getClass();
public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
}
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
public final void wait() throws InterruptedException {
wait(0);
}
public final native void wait(long timeout) throws InterruptedException;
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);
}
public final native void notify();
public final native void notifyAll();
protected native Object clone() throws CloneNotSupportedException;
protected void finalize() throws Throwable { }
}
接下来依次讲解每一个方法。
在不重写构造方法的情况下,所有类默认都拥有一个无参的构造方法。现在有Son、Father、GrandFather...依次继承的类,创建Son类对象会依次调用父类,祖父类...的无参构造方法。所以,创建任何对象,都会调用Object的构造方法。
该方法返回对象运行时的类型。看代码:
Number n = 0;System.out.println(c.getName());
最后打印出来的类型并不是Number,而是Integer。
<>是泛型,jdk1.5引入的特性,编译时类型安全检测机制。泛型只存在于java的编译期,编译生成字节码文件后泛型会被擦除。泛型的本质是参数化类型,类型被指定为一个参数。
?是通配符, ? extends Number表示Number的任意子类。Class extends Number> c = n.getClass();编译时会检查n.getClass对应的类型是不是Number类型或者Number子类型。
通俗地讲, 我们指定了容器可以装桌子,编译时就只能装桌子,装椅子就会报错。因为编译后,泛型擦除,所以 在运行时可以装椅子
hashCode是JDK根据 对象的地址或者字符串或者数字 算出来的int类型的数值。
重写hashCode()常用方法是使用Objects.hash(Object..args), 内部调用了Arrays.hashCode(Object a[]), 内部实现:
int result = 1;return result
默认实现是使用了 == ,比较的是对象的内存地址。
在不重写equals方法的情况下,如果两个对象equals, 表示是同一个对象,那么hashcode必定相同。但是如果两个对象的hashcode相同,它们不一定equals, 也就是说不一定是同一个对象。
在重写equals的情况下,如果两个对象equals,那么它们不一定==,hashcode也不一定相同,如果要想让hashcode相同,需要重写hashCode方法。默认返回 class的名称+@+hashcode的16进制字符串,比如: java.lang.Object@7852e922
释放对象锁,进入等待状态,需要通过notifiy/notifyAll方法唤醒。
wait()在多个线程等待同一个对象锁的情况,最好放在while循环内执行,因为可以添加wait的条件,当条件不满足,就继续wait。举个通俗一点的例子:比如A,B,C三个人都在同一个窗口抢着买东西,A首先占领了窗口,买完后notifyAll,可能是B,也可能是C,即便此时C抢到了窗口,但是C钱不够,需要等家人送来钱,所以C不满足条件,应该选择继续wait,把窗口让给B。
wait(long timeout) notifiy/notifyAll方法或者指定的时间已过, 都会被唤醒notifyAll 唤醒所有等待当前对象锁的线程
demo:
public class Inc extends Thread{
ActObject obj;
public Inc(ActObject obj){
this.obj = obj;
}
@Override
public void run() {
obj.add();
}
}
public class Dec extends Thread{
ActObject obj;
public Dec(ActObject obj){
this.obj = obj;
}
@Override
public void run() {
obj.del();
}
}
public class ActObject{
public int count = 100;
public Object obj = new Object();
public synchronized void add() {
System.out.println("Add---before " + count);
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
System.out.println("Add---after " + count);
}
public synchronized void del() {
System.out.println("Del---before " + count);
count--;
notifyAll();
System.out.println("Del---after " + count);
}
}
ActObject obj = new ActObject();
new Inc(obj).start();
new Dec(obj).start();
打印结果:
Add---before 100
Del---before 100
Del---after 99
Add---after 100
finalize()是Object的protected方法,垃圾回收器回收对象之前会调用该方法,我们可以在子类重写这个方法,"JVM只会至多调用finalize一次,即使该对象'复活'也是如此。程序员手动调用多少次不影响JVM的行为"。
GC机制:通过一系列的“GC Roots”对象作为起点进行搜索,如果在“GC Roots”和一个对象之间没有可达路径,则称该对象是不可达的,不过要注意的是被判定为不可达的对象不一定就会成为可回收对象。被判定为不可达的对象要成为可回收对象必须至少经历两次标记过程,如果在这两次标记过程中仍然没有逃脱成为可回收对象的可能性,则基本上就真的成为可回收对象了。
Java的GC机制减少了内存泄漏,提高了安全性,也减少了开发者的工作量。浅复制:对象内的基本类型变量会进行复制,对象内的引用变量不会进行复制。
深度复制:对象内的基本类型变量会进行复制,对象内的引用变量也会进行复制。