菜鸟笔记
提升您的技术认知

java之Object类

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方法创建对象步骤

  1. 在需要调用clone方法的对象上添加实现Cloneable接口
  2. 复写clone方法,在自己的克隆方法中调用父类的clone方法,将返回值强转为本类类型,并将当前的方法修饰符改为public
  3. 在测试中调用对象的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的时候,克隆对象是一个新对象,而且,克隆对象中的成员变量也要求是一个新对象

开发步骤

  1. 修改成员类实现Cloneable接口
  2. 修改成员类重写clone方法
  3. 修改要克隆的类的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();
    }
}