对象克隆:
protected Object clone()创建并返回一个对象的拷贝

垃圾回收:
protected void finalize()**当 GC (垃圾回收器)确定不存在对该对象的有更多引用时,由对象的垃圾回收器调用此方法。

获取类信息:
Class<?> getClass()获取对象的运行时对象的类

对比对象相等:
boolean equals(Object obj)比较两个对象是否相等
int hashCode()获取对象的 hash 值

转成字符串:
String toString()**返回对象的字符串表示形式

线程相关:
void wait()让当前线程进入等待状态。直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。
void wait(long timeout)让当前线程处于等待(阻塞)状态,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过参数设置的timeout超时时间。
void wait(long timeout, int nanos)wait(long timeout) 方法类似,多了一个 nanos 参数,这个参数表示额外时间(以纳秒为单位,范围是 0-999999)。 所以超时的时间还需要加上 nanos 纳秒
void notify()唤醒在该对象上等待的某个线程
void notifyAll()唤醒在该对象上等待的所有线程

clone方法

  • 用途:使自定义对象可复制
  • 使用:在自定义类中实现Cloneable接口,并重写clone方法
  • 注意事项:当对象的字段存在引用类型时应注意浅拷贝和深拷贝的问题
    • 浅拷贝仅复制变量的值,则对于引用字段来说复制了其地址,因而修改clone出的对象会影响原对象
    • 深拷贝则会对对象的引用字段实现拷贝
  • 举例:
    浅拷贝

    1. public class Student implements Cloneable {
    2. private String name;
    3. private Professor professor; // 引用类型字段
    4. public String getName() {
    5. return this.name;
    6. }
    7. public void setName(String name) {
    8. this.name = name;
    9. }
    10. public Professor getProfessor() {
    11. return professor;
    12. }
    13. public void setProfessor(Professor professor) {
    14. this.professor = professor;
    15. }
    16. // 实现clone方法
    17. public Object clone() throws CloneNotSupportedException{
    18. return super.clone();
    19. }
    20. }
    21. public class Professor {
    22. private String name;
    23. public String getName() {
    24. return name;
    25. }
    26. public void setName(String name) {
    27. this.name = name;
    28. }
    29. }
    30. // 浅拷贝
    31. public class ShadowCopy {
    32. public static void main(String[] args) {
    33. Professor p1 = new Professor();
    34. p1.setName("Professor Zhang");
    35. Student s1 = new Student();
    36. s1.setName("xiao ming");
    37. s1.setProfessor(p1);
    38. try {
    39. Student s2 = (Student) s1.clone(); // clone
    40. Professor p2 = s2.getProfessor();
    41. p2.setName("Professor Li"); // s1和s2的引用字段指向的是同一个professor对象,修改s2的引用字段会影响s1的引用字段
    42. s2.setProfessor(p2);
    43. } catch (CloneNotSupportedException e) {
    44. e.printStackTrace();
    45. }
    46. }
    47. }
  • 深拷贝

    1. public class Professor implements Cloneable {
    2. ...
    3. // 实现clone方法
    4. public Object clone() throws CloneNotSupportedException{
    5. return super.clone();
    6. }
    7. }
    8. public class Student implements Cloneable {
    9. ...
    10. // 实现clone方法
    11. public Object clone() throws CloneNotSupportedException{
    12. Student newStudent = (Student) super.clone();
    13. newStudent.professor = (Professor) this.professor.clone(); // 对student对象的引用字段进行clone
    14. return newStudent;
    15. }
    16. }

    equals()、hashCode()

  • 用途:比较两个对象

  • 使用:使用由Object类继承而来的equals方法或在自定义类中重写equals方法
    • 若不重写,则equals方法默认使用==比较对象
  • 注意事项:
    • equals方法和相等操作符的区别
    • 重写equals方法后必须重写hashCode方法,二者应在逻辑上保持一致
  • 举例:

    1. class People {
    2. private String name;
    3. private int age;
    4. public People(String name,int age) {
    5. this.name = name;
    6. this.age = age;
    7. }
    8. @Override
    9. public boolean equals(Object obj) {
    10. return this.name.equals(((People)obj).name) && this.age == ((People)obj).age; // 即通过比较属性值判断两对象是否相等
    11. }
    12. }
    13. public class Main {
    14. public static void main(String[] args) {
    15. People p1 = new People("Jack", 12);
    16. People p2 = new People("Jack", 12);
    17. System.out.println(p1.equals(p2)); // true
    18. }
    19. }
  • 用途:将对象的相关信息映射成散列值,用于在集合中快速查找

  • 使用:使用由Object继承而来的hashCode方法或在自定义类中重写hashCode方法
    • 若不重写,hashCode方法默认返回对象的存储地址
  • 注意实现:
    • equals方法和hashCode方法的关系
    • 重写hashCode方法后必须重写equals方法,二者应在逻辑上保持一致
  • 举例
    ``` class People{ private String name; private int age;

    public People(String name,int age) {

    1. this.name = name;
    2. this.age = age;

    }

    @Override public boolean equals(Object obj) {

    1. return this.name.equals(((People)obj).name) && this.age == ((People)obj).age;

    }

    @Override public int hashCode() {

    1. return name.hashCode()*37+age;
    2. }

    }

public class Main {

  1. public static void main(String[] args) {
  2. People p1 = new People("Jack", 12);
  3. System.out.println(p1.hashCode());
  4. HashMap<People, Integer> hashMap = new HashMap<People, Integer>();
  5. hashMap.put(p1, 1);
  6. System.out.println(hashMap.get(new People("Jack", 12))); // 输出:1
  7. }

}

  1. <a name="qMpgA"></a>
  2. ## getClass方法
  3. - 用途:获得对象对应的类名<br />
  4. - 注意事项:getClass方法和class方法的区别
  5. - getClass方法类的实例的方法(即获得的是运行时对象所属的类)
  6. - class方法是类的方法(在编译时即可确定)
  7. - 举例:<br />

class A {} public class Test { public static void main(String[] args) { A a = new A(); System.out.println(a.getClass()); // class A System.out.println(A.class()); // class A } }

  1. <a name="BMzCq"></a>
  2. ## toString方法
  3. - 用途:返回对象的字符串表示<br />
  4. - 使用:
  5. - Object的toString方法的返回值为类名+@+十六进制的对象的哈希值,等价于:<br />`getClass().getName() + '@' + Integer.toHexString(hashCode())`<br />
  6. - 推荐在自定义类中重写toString方法以将对象包含的信息以直观的方式展示<br />
  7. - 举例:<br />

// 例1: Integer i = new Integer(50); ArrayList list = new ArrayList(); list.add(50); list.add(“Hello World”); System.out.println(“” + i.toString()); // 50 System.out.println(“” + list.toString()); // [50, Hello World] // —————————————————————————————————- // 例2: public class Student implements Cloneable {

  1. private String name;
  2. private int age;
  3. public void setName(String name) {
  4. this.name = name;
  5. }
  6. public void setAge(int age) {
  7. this.age = age;
  8. }
  9. @Override
  10. public String toString() {
  11. return "Student [name=" + name + ", age=" + age + "]";
  12. }

} public class Main { public static void main(String[] args) { Student student = new Student(); student.setName(“Xiao Ming”); student.setAge(20); System.out.println(student.toString()); // Student [name = Xiao Ming, age = 20] } }

  1. <a name="qeJMf"></a>
  2. ## wait(long timeout)、wait(long timeout, int nanos)、wait()
  3. 1)wait()<br />  ![](https://cdn.nlark.com/yuque/0/2021/png/251474/1615536461248-676bb394-e95b-4317-aac2-d4a0f0376da5.png#align=left&display=inline&height=73&margin=%5Bobject%20Object%5D&originHeight=73&originWidth=567&size=0&status=done&style=none&width=567)<br />2)wait(long timeout)<br />  ![](https://cdn.nlark.com/yuque/0/2021/png/251474/1615536461288-1e018c74-9ffd-4e0f-b142-fe415da9738d.png#align=left&display=inline&height=35&margin=%5Bobject%20Object%5D&originHeight=35&originWidth=739&size=0&status=done&style=none&width=739)<br />3)wait(long timeout,int naos)<br />  ![](https://cdn.nlark.com/yuque/0/2021/png/251474/1615536461247-ba5da994-0c1b-4f22-97a9-2484059101d9.png#align=left&display=inline&height=297&margin=%5Bobject%20Object%5D&originHeight=402&originWidth=812&size=0&status=done&style=none&width=600)<br />  什么意思呢?<br />    ![](https://cdn.nlark.com/yuque/0/2021/png/251474/1615536461284-2d7e09b5-1430-4446-bfbd-993a67ea460a.png#align=left&display=inline&height=204&margin=%5Bobject%20Object%5D&originHeight=204&originWidth=944&size=0&status=done&style=none&width=944)<br />  方法中的异常:<br />    ![](https://cdn.nlark.com/yuque/0/2021/png/251474/1615536461272-666e6aa6-5b36-4770-a733-5280a96650a4.png#align=left&display=inline&height=76&margin=%5Bobject%20Object%5D&originHeight=76&originWidth=848&size=0&status=done&style=none&width=848)   <br />wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,<br />如果在规定时间内没有获得锁就返回。
  4. 调用该方法后当前线程进入睡眠状态,直到以下事件发生。<br />(1)其他线程调用了该对象的notify方法。<br />(2)其他线程调用了该对象的notifyAll方法。<br />(3)其他线程调用了interrupt中断该线程。<br />(4)时间间隔到了。<br />此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。
  5. <a name="aN3mV"></a>
  6. ## notify()、notifyAll()
  7. 源码:

public final native void notify(); public final native void notifyAll(); ``` 方法注释:
Object类 - 图1
Object类 - 图2

finalize()方法


Object类 - 图3
该方法用于释放资源。因为无法确定该方法什么时候被调用,很少使用。

Java允许在类中定义一个名为finalize()的方法。它的工作原理是:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法。并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
关于垃圾回收,有三点需要记住:
  1、对象可能不被垃圾回收。只要程序没有濒临存储空间用完的那一刻,对象占用的空间就总也得不到释放。
  2、垃圾回收并不等于“析构”。
  3、垃圾回收只与内存有关。使用垃圾回收的唯一原因是为了回收程序不再使用的内存。
finalize()的用途:

  无论对象是如何创建的,垃圾回收器都会负责释放对象占据的所有内存。这就将对finalize()的需求限制到一种特殊情况,即通过某种创建对象方式以外的方式为对象分配了存储空间。
  不过这种情况一般发生在使用“本地方法”的情况下,本地方法是一种在Java中调用非Java代码的方式。