对象克隆:
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出的对象会影响原对象
- 深拷贝则会对对象的引用字段实现拷贝
举例:
浅拷贝public class Student implements Cloneable {
private String name;
private Professor professor; // 引用类型字段
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Professor getProfessor() {
return professor;
}
public void setProfessor(Professor professor) {
this.professor = professor;
}
// 实现clone方法
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
public class Professor {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// 浅拷贝
public class ShadowCopy {
public static void main(String[] args) {
Professor p1 = new Professor();
p1.setName("Professor Zhang");
Student s1 = new Student();
s1.setName("xiao ming");
s1.setProfessor(p1);
try {
Student s2 = (Student) s1.clone(); // clone
Professor p2 = s2.getProfessor();
p2.setName("Professor Li"); // s1和s2的引用字段指向的是同一个professor对象,修改s2的引用字段会影响s1的引用字段
s2.setProfessor(p2);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
深拷贝
public class Professor implements Cloneable {
...
// 实现clone方法
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
public class Student implements Cloneable {
...
// 实现clone方法
public Object clone() throws CloneNotSupportedException{
Student newStudent = (Student) super.clone();
newStudent.professor = (Professor) this.professor.clone(); // 对student对象的引用字段进行clone
return newStudent;
}
}
equals()、hashCode()
用途:比较两个对象
- 使用:使用由Object类继承而来的equals方法或在自定义类中重写equals方法
- 若不重写,则equals方法默认使用==比较对象
- 注意事项:
- equals方法和相等操作符的区别
- 重写equals方法后必须重写hashCode方法,二者应在逻辑上保持一致
举例:
class People {
private String name;
private int age;
public People(String name,int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
return this.name.equals(((People)obj).name) && this.age == ((People)obj).age; // 即通过比较属性值判断两对象是否相等
}
}
public class Main {
public static void main(String[] args) {
People p1 = new People("Jack", 12);
People p2 = new People("Jack", 12);
System.out.println(p1.equals(p2)); // true
}
}
用途:将对象的相关信息映射成散列值,用于在集合中快速查找
- 使用:使用由Object继承而来的hashCode方法或在自定义类中重写hashCode方法
- 若不重写,hashCode方法默认返回对象的存储地址
- 注意实现:
- equals方法和hashCode方法的关系
- 重写hashCode方法后必须重写equals方法,二者应在逻辑上保持一致
举例
``` class People{ private String name; private int age;public People(String name,int age) {
this.name = name;
this.age = age;
}
@Override public boolean equals(Object obj) {
return this.name.equals(((People)obj).name) && this.age == ((People)obj).age;
}
@Override public int hashCode() {
return name.hashCode()*37+age;
}
}
public class Main {
public static void main(String[] args) {
People p1 = new People("Jack", 12);
System.out.println(p1.hashCode());
HashMap<People, Integer> hashMap = new HashMap<People, Integer>();
hashMap.put(p1, 1);
System.out.println(hashMap.get(new People("Jack", 12))); // 输出:1
}
}
<a name="qMpgA"></a>
## getClass方法
- 用途:获得对象对应的类名<br />
- 注意事项:getClass方法和class方法的区别
- getClass方法类的实例的方法(即获得的是运行时对象所属的类)
- class方法是类的方法(在编译时即可确定)
- 举例:<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 } }
<a name="BMzCq"></a>
## toString方法
- 用途:返回对象的字符串表示<br />
- 使用:
- Object的toString方法的返回值为类名+@+十六进制的对象的哈希值,等价于:<br />`getClass().getName() + '@' + Integer.toHexString(hashCode())`<br />
- 推荐在自定义类中重写toString方法以将对象包含的信息以直观的方式展示<br />
- 举例:<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 {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
} 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] } }
<a name="qeJMf"></a>
## wait(long timeout)、wait(long timeout, int nanos)、wait()
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 />如果在规定时间内没有获得锁就返回。
调用该方法后当前线程进入睡眠状态,直到以下事件发生。<br />(1)其他线程调用了该对象的notify方法。<br />(2)其他线程调用了该对象的notifyAll方法。<br />(3)其他线程调用了interrupt中断该线程。<br />(4)时间间隔到了。<br />此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。
<a name="aN3mV"></a>
## notify()、notifyAll()
源码:
public final native void notify();
public final native void notifyAll();
```
方法注释:
finalize()方法
该方法用于释放资源。因为无法确定该方法什么时候被调用,很少使用。
Java允许在类中定义一个名为finalize()的方法。它的工作原理是:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法。并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
关于垃圾回收,有三点需要记住:
1、对象可能不被垃圾回收。只要程序没有濒临存储空间用完的那一刻,对象占用的空间就总也得不到释放。
2、垃圾回收并不等于“析构”。
3、垃圾回收只与内存有关。使用垃圾回收的唯一原因是为了回收程序不再使用的内存。
finalize()的用途:
无论对象是如何创建的,垃圾回收器都会负责释放对象占据的所有内存。这就将对finalize()的需求限制到一种特殊情况,即通过某种创建对象方式以外的方式为对象分配了存储空间。
不过这种情况一般发生在使用“本地方法”的情况下,本地方法是一种在Java中调用非Java代码的方式。