Object类
前言
含义:Object类是所有Java类的祖先,也就是说我们所说的”顶级父类”
注意:
- 它存在于java.lang.Object,这个包不需要我们手动导包
- 每个类都使用Object作为超类.所有对象(包括数组)都实现这个类的方法.
- 如果在类的声明中未使用extends关键字指明其父类,则默认继承Object类
以下两种写法效果完全相同
class Person { }
class Person extends Object { }
常用方法
hashCode()
public native int hashCode();
理解:该方法用于哈希查找,不同的hash值对应不同的对象。
getClass()
public final native Class<?> getClass();
理解:final方法,返回Class类型的对象,反射来获取对象。
toString()
作用:对对象进行介绍,一般子类对父类提供的toString都不满意,都要进行重写
public String toString()
本方法用于返回对应对象的字符串表示
public class Test {
public static void main(String[] args) {
Gril lili = new Gril("lili", 18);
System.out.println(lili);//省略了.toString()
System.out.println(lili.toString());//地址
Person lan = new Person("lan", 23);
System.out.println(lan);//Person{name='lan', age=23}
}
}
class Person{
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//重写toString
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
class Gril{
String name;
int age;
public Gril(String name, int age) {
this.name = name;
this.age = age;
}
}
注意:
- 在使用对象直接输出的时候,默认输出的是一个对象在堆内存上的包名、类名以及地址值;如若要输出该对象的内容,则要覆写
toString()
方法 - String作为信息输出的重要数据类型,在Java中所有的数据类型只要遇见String就执行了
+拼接
,都要求其变为字符串后连接,而所有对象想要变为字符串就默认用toString( )方法
finalize()
protected void finalize() throws Throwable { }
作用:清理空间,释放资源
执行者:
- jvm的垃圾回收期,简称gc
- Object的子类对象(就是程序员自己手动调用,不建议)
//该方法用于回收资源,当System.gc();之后由垃圾回收器调用,用来回收垃圾
@Override
protected void finalize() throws Throwable {
super.finalize();
}
注意:
- 重写finalize方法语句中的super.finalize()意味着可以实现从下到上实现finalize的调用,即先释放自己的资源再释放父类的资源
- 程序员无权调用垃圾回收器,但程序员可以调用System.gc()方法通知GC回收垃圾,但是jvm规范中并不保证你调用了就一定能执行垃圾回收
- finalize方法是java提供给程序员主动来调用,释放对象占用的内存空间,但尽量少用,因为这样会扰乱GC的正常垃圾回收进程,影响GC效率
equals()
public boolean equals(Object obj) {return (this == obj);}
- ==用来判断两个变量的值是否相等。如果变量是基本数据类型,则直接比较;如果变量是引用类型,则比较引用内存的首地址。
- equals比较两个对象是否一样,实际上就是调用对象equals方法进行比较。equals 默认情况下是采用==比较,只是很多类重写了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。
import java.util.Objects;
public class Test2 {
public static void main(String[] args) {
Phone h1 = new Phone("华为", 55.5);
Phone h2 = new Phone("华为", 55.5);
System.out.println(h1==h2);
System.out.println(h1.equals(h2));//true——重写了
}
}
class Phone{
String brand;
double price;
public Phone(String brand, double price) {
this.brand = brand;
this.price = price;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Phone phone = (Phone) o;
return Double.compare(phone.price, price) == 0 &&
Objects.equals(brand, phone.brand);
}
@Override
public int hashCode() {
return Objects.hash(brand, price);
}
}
wait()
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException
public final void wait() throws InterruptedException {wait(0);}
理解:当调用wait()方法时就把线程本来已经得到的同步锁释放掉,并进入等待队列(等待池),让其他线程可以去抢这个锁,当其他线程调用notify()或者notifyAll()时才会去通知之前的线程可以去争抢锁了而不是立马就得到锁
注意:wait()方法只能用在同步代码块或同步方法中
notify()
public final native void notify();
作用:用于随机通知一个等待池中的对象停止等待
notifyAll()
public final native void notifyAll();
作用:通知等待池中的所有对象停止等待
clone()
protected native Object clone() throws CloneNotSupportedException;
理解:保护方法,实现对象的浅复制,只有实现了Cloneable
接口才可以调用该方法,否则抛出CloneNotSupportedException异常。
clone()方法详解
克隆:创建并返回对象的一个副本——按照原对象,创建一个新对象(复制原对象的内容)
创建对象的方式:用new关键字实例化、反射、克隆
使用克隆的原因:使用反射或实例化两个或多个内容一样的对象比较麻烦
使用clone方法创建对象步骤
- 在需要调用clone方法的对象上添加实现Cloneable接口
- 复写clone方法,在自己的克隆方法中调用父类的clone方法,将返回值强转为本类类型,并将当前的方法修饰符改为public
- 在测试中调用对象的clone方法
克隆方法存在意义:使用clone方法可以大大减少创建重复的对象代码
案例
public class CloneTest {
public static void main(String[] args) throws Exception {
Student student = new Student();
student.setName("lili");
Children children = new Children();
children.setName("lala");
student.setChildren(children);
//克隆
Student clone = student.clone();
//内容一样,对象不同;成员对象内容和地址均一样
System.out.println(student+":"+student.hashCode()+student.getChildren()+":"+student.getChildren().hashCode());
System.out.println(clone+":"+clone.hashCode()+clone.getChildren()+":"+clone.getChildren().hashCode());
}
}
class Student implements Cloneable{
private String name;
private Children children;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Children getChildren() {
return children;
}
public void setChildren(Children children) {
this.children = children;
}
@Override
protected Student clone() throws CloneNotSupportedException {
return (Student)super.clone();
}
}
class Children{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Children{" +
"name='" + name + '\'' +
'}';
}
}
注意:
- 以上克隆出来的内容一样,但hash值不同
- 如果对象里面的成员存在另一对象,那么复制前和复制后的两个原对象内容相同,地址不同,里面的成员对象内容和地址均相同(这样的复制也称浅表复制)
- clone方法的默认复制操作是浅表复制
浅表复制
浅表复制:对象内容完全复制,遇到成员对象只将之前的引用复制过去
浅表复制特点
- 克隆的对象是一个新对象
- 克隆对象的成员变量与原对象的成员变量是同一个数据(底层hash值一致)
浅表复制的弊端:仅仅创建新的对象,对象成员内容底层hash值是一致的,因此,不管原对象还是克隆对象,只要有其中一个修改了成员的数据,就会影响所有的原对象和克隆对象
深层复制
深层复制:不仅执行clone的时候,克隆对象是一个新对象,而且,克隆对象中的成员变量也要求是一个新对象
开发步骤
- 修改成员类实现Cloneable接口
- 修改成员类重写clone方法
- 修改要克隆的类的clone方法,在clone方法中调用成员类的clone方法
public class CloneTest {
public static void main(String[] args) throws Exception {
Student student = new Student();
student.setName("lili");
Children children = new Children();
children.setName("lala");
student.setChildren(children);
//克隆
Student clone = student.clone();
//内容一样,对象不同;成员对象内容一样,地址不同
System.out.println(student+":"+student.hashCode()+student.getChildren()+":"+student.getChildren().hashCode());
System.out.println(clone+":"+clone.hashCode()+clone.getChildren()+":"+clone.getChildren().hashCode());
}
}
class Student implements Cloneable{
private String name;
private Children children;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Children getChildren() {
return children;
}
public void setChildren(Children children) {
this.children = children;
}
@Override
protected Student clone() throws CloneNotSupportedException {
Student clone = (Student) super.clone();
clone.setChildren(children.clone());
return clone;
}
}
class Children implements Cloneable{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Children{" +
"name='" + name + '\'' +
'}';
}
@Override
protected Children clone() throws CloneNotSupportedException {
return (Children)super.clone();
}
}