Object
一、类路径:
java.lang.Object;
二、类属性:
1、getClass():
getClass()方法返回的是对象运行时类,方法是final类型的,不可被修改,表示对象的运行时类是不可被改变的;
2、hashCode():
hashCode方法返回的是对象的哈希值,它要求被多次调用后,返回的值是不能产生变化的,通常用于在HASH类存储集合中确定存储的位置,一般是与equals配合使用的;
3、equals():
1、 equals方法用来判断两个对象是否相等,该方便如果没有重写,是判断对象地址是否相等;
2、在java的一些类型中,对equals方法进行了重写,是判断对象的属性是否相等,比如String、Integer等;
3、如果重写了equals方法,一般都需要重写hashCode方法,并满足一下规则:
equals重写规则:
自反性:对于任何非null的对象a,a.equals(a) 返回值必须为true;
对称性: 对于任何非null对象a、b;如果a.equals(b)为true,则b.equals(a)也必须为true;
传递性:对于任何非null对象a、b、c;如果a.equals(b)、b.equals(c)都为true,则a.equals(c)也必须为true;
一致性:对于任何非null对象a、b;如果a、b的属性都没有发生改变,则无论调用多少次a.equals(b),最终的返回结果都是不变的;
对于任何的非null对象a;a.equals(null)都应该返回false;
hashCode重写规则:
对于任何非null对象a、b;如果a.equals(b)为true,则必须保证a、b的hashCode的值必须相等;
对于任何非null对象a、b;如果a.equals(b)为false,则a、b的hashCode不一定相等;
对于任何非null对象a、b;如果a、b的hashCode相等,则a、b不一定相等;
常见重写方式(这里参考IDEA的方式生成)
public class Person {
private String name;
private int age;
private float height;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public float getHeight() {
return height;
}
public void setHeight(float height) {
this.height = height;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Float.compare(person.height, height) == 0 &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age, height);
}
}
public class Person {
private String name;
private int age;
private float height;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public float getHeight() {
return height;
}
public void setHeight(float height) {
this.height = height;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person person = (Person) o;
return age == person.age &&
Float.compare(person.height, height) == 0 &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age, height);
}
}
引申阅读:
我们思考,在重写equals方法 时,判断两个对象是否是同一种对象类型时,用getClass和用instanceOf有什么区别呢?
4、clone():
clone方法为拷贝对象,类必须实现Cloneable接口(仅仅只是一个标记,标识此类可以被拷贝),并重写clone方法,它分为深拷贝和浅拷贝:
浅拷贝:只对基本类型的值进行复制,引用类型的对象,都是直接复制对象引用的:
深拷贝:引用类型对象本身也实现Cloneable接口,并重写了clone方法,此时对引用类型对象的拷贝也就是深拷贝了:
如下图中,Person类就实现了深拷贝:
public class Person implements Cloneable {
public static class Sun implements Cloneable {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
protected Sun clone() throws CloneNotSupportedException {
return (Sun) super.clone();
}
}
private Sun sun;
private String name;
private int age;
public Sun getSun() {
return sun;
}
public void setSun(Sun sun) {
this.sun = sun;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public Person clone() throws CloneNotSupportedException {
Person newPerson = (Person) super.clone();
newPerson.sun = sun.clone();
return newPerson;
}
}
5、toString():
toString方法默认输出类名及哈希值,你可以重写成你想要的任何信息输出;
6、finalize():
finalize方法,该方法如果有重写(一般用来保证对资源的释放,如IO流(FileInputStream就重写了该方法),但是一般不推荐这么做),垃圾回收机制在第一次回收该对象的时候会调用该方法(如果没有重写该方法,对象会被直接回收),当在第二次触发垃圾回收时,不会再调用该方法,会直接回收对象(如果你在该方法中,强行给该对象增加强引用,则可以救活该对象);
7、wait()、wait(long)、notify()、notifyAll():
这几个方法放在一起讲,是因为他们是相互协作的,下面详细介绍:
1、这三个方法,一般是用在多线程的生产者和消费者模式中,生产者不停的生产,消费者不停的消费,必须考虑线程安全问题,所以他们都会在同步代码块当中(如果不在同步代码块中使用,会抛出IllegalMonitorStateException异常);
2、这三个方法一般都是放在循环语句当中,用于循环生产和消费;
3、生产者生产产品之后,调用wait()方法使线程进入等待状态,或者调用wati(long)方法,让线程进入等待状态(如果超过一定时间,线程将自动被唤醒), 而调用wait后当前生产者(消费者)线程将释放锁;
4、生产者在调用wait之前,必须调用notify或者notifyAll唤醒其它线程,其它线程被唤醒后,会共同竞争锁,拿到锁的线程将进行消费(或生产);
典型的应用如下所示:
/**
* 生产者
*/
class Producter extends Thread {
@Override
public void run() {
while (run) {
synchronized (queue) {
while (queue.size() >= MAX_CAPACITY * 2) {
try {
System.out.println("缓冲队列已满,等待消费");
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
String string = UUID.randomUUID().toString();
queue.put(string);
System.out.println("生产:" + string);
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 生产完后立马通知消费
queue.notifyAll();//通知生产者和消费者
}
}
}
}
/**
* 消费者
*/
class Consumer extends Thread {
@Override
public void run() {
while (run) {
synchronized (queue) {
while (queue.isEmpty()) {
try {
System.out.println("队列为空,等待生产");
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
System.out.println("消费:" + queue.take());
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 消费后立马通知生产
queue.notifyAll();//通知生产者和消费者
}
}
}
}