Object
the parent class for all the class.
public class Object {
//注册本地方法
private static native void registerNatives();
static {
registerNatives();
}
//获取运行时对象的类
public final native Class<?> getClass();
//获取对象的hash值
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 notifyAll();
//当前线程调用对象的wait方法,当前线程释放对象锁,进入等待队列,依靠其他线程唤醒,或等待时间到后自动唤醒
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);
}
//当前线程调用对象的wait方法,当前线程释放对象锁,进入等待队列,依靠其他线程唤醒
public final void wait() throws InterruptedException {
wait(0);
}
protected void finalize() throws Throwable { }
}
getclass()
获取运行时对象的类
hashcode()
Hash(散列),将任意长度的输入,通过hash算法(常见Hash算法)变换成固定长度的输出,输出值就是hashcode(散列值,哈希值)。关于hashcode的一些注意事项:
- 如果散列表中存在和散列原始输入K相等的记录,那么K必定在f(K)的存储位置上
- 不同输入经过hash算法可能得到同一个hashcode,这种现象被称为hash碰撞
- 如果两个hash值不同(前提是同一Hash算法),那么这两个Hash值对应的原始输入必定不同
HashCode作用:JVM每new一个Object,它都会将这个Object丢到一个Hash表中去,这样的话,下次做Object的比较或者取这个对象的时候(读取过程),它会根据对象的HashCode再从Hash表中取这个对象。这样做的目的是提高取对象的效率Hashcode确定对象的存储位置,便于快速查找
equals()
equals()是用于比较两个对象的是否相等的
- 比较类型相同
- 比较成员变量的值相等
一般推荐如果类重写了equals()方法,那么hashcode()也要重写 具体原因如下
public class MyHash {
public static void main(String[] args) {
MyBusiness m1 = new MyBusiness();
MyBusiness m2 = new MyBusiness();
MyBusiness m3 = new MyBusiness();
Set testSet =new HashSet<MyBusiness>();
testSet.add(m1);
testSet.add(m2);
testSet.add(m3);
System.out.println(testSet.size()); // return 3
}
}
class MyBusiness{
private String nameString;
private int age;
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MyBusiness other = (MyBusiness) obj;
if (age != other.age)
return false;
if (nameString == null) {
if (other.nameString != null)
return false;
} else if (!nameString.equals(other.nameString))
return false;
return true;
}
}
我们重写了Mybusiness类的equals方法,此时m1,m2,m3三个对象的类型一致,并且成员变量的值一致,因此m1 equals m2 equals m3,我们将三个对象放入set集合中(Set中不会出现重复的数据),但是我们通过打印Set的size方法吗,却发现返回值是3,因此说明Set集合认为那三个对象是不同的。 原因是HashSet使用了Object的hashcode方法,因为hashcode()返回的是对象存储地址经过特定算法返回的值,因此m1,m2,m3的hashcode都不相同,(hashcode不同,则对象一定不同,hashcode相同,对象可能相同可能不同),所以HashSet的size为3.
public class MyHash {
public static void main(String[] args) {
MyBusiness m1 = new MyBusiness();
MyBusiness m2 = new MyBusiness();
MyBusiness m3 = new MyBusiness();
Set testSet =new HashSet<MyBusiness>();
testSet.add(m1);
testSet.add(m2);
testSet.add(m3);
System.out.println(testSet.size()); //return 1
}
}
class MyBusiness{
private String nameString;
private int age;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((nameString == null) ? 0 : nameString.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MyBusiness other = (MyBusiness) obj;
if (age != other.age)
return false;
if (nameString == null) {
if (other.nameString != null)
return false;
} else if (!nameString.equals(other.nameString))
return false;
return true;
}
}
然后我们同时重写了equals和hashcode方法,此时Hashset和size()返回值是1,此时m1,m2,m3三个对象的hashcode值一致,被划分到同一块区域存储(此时依旧不能保证三个对象相等),然后HashSet会调用m1,m2,m3对象的equals方法,判断出三个对象相等,因此相等的对象不会被存储,HashSet的size只为1
clone()
创建并返回该对象的一个拷贝
wait()/wait(long)
当前线程调用对象的wait()方法,当前线程释放对象锁,进入等待队列,依靠其他线程唤醒(notify()或notifyAll())或者wait(long)等待时间到自动唤醒。
nofity()/notifyAll()
notify()唤醒在此对象监视器上处于等待状态的单个线程,选择是任意的。notifyAll()唤醒在此对象监视器上所有处于等待状态的线程。
//wait() 和notify()实现线程交替执行
public class TicketTest {
public static void main(String[] args) {
Ticket ticket =Ticket.getInstance();
new Thread(new Runnable() {
@Override
public void run() {
ticket.sellTicket();
}
}).start();
ticket.sellTicket();
}
}
class Ticket{
private static Ticket ticket;
private int total = 100;
private Lock reentrantLock = new ReentrantLock();
private String last;
public static Ticket getInstance() {
if(ticket == null) {
ticket=new Ticket();
}
return ticket;
}
public synchronized void sellTicket() {
String threadName = Thread.currentThread().getName();
while(true) {
try {
//两次线程的名字一致,是同一线程,则线程释放同步锁,等待其他线程执行后将其唤醒
if(threadName.equals(last)) {
//当前线程进入等待状态,并且释放对象锁
this.wait();
}
if(this.total>0) {
this.total--;
System.out.println(threadName + " sold one ticket, tickets remain: " + total);
}else {
System.out.println("tickets sold out");
System.exit(0);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
last = threadName;
//线程执行结束后,唤醒此对象监视器上处于等待状态的单个线程
this.notify();
}
}
}
}
finalize()
用于实例对象被垃圾回收器回收的时触发的操作,当 GC (垃圾回收器) 确定不存在对该对象的有更多引用时,对象的垃圾回收器就会调用这个方法