请你谈谈对Object类的理解?

Object是java所有类的基类,是整个类继承结构的顶端,也是最抽象的一个类。大家天天都在使用toString()、equals()、hashCode()、wait()、notify()、getClass()等方法

1getClass()方法

类加载的第一阶段类的加载就是将.class文件加载到内存,并生成一个java.lang.Class对象的过程。getClass()方法就是获取这个对象。

2hashCode()方法

这是一个public的方法,所以 子类可以重写它。这个方法返回当前对象的hashCode值,这个值是一个整数范围内的(-2^31 ~ 2^31 - 1)数字。

在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改;

如果两个对象 x.equals(y) 方法返回true,则x、y这两个对象的hashCode必须相等。

如果两个对象x.equals(y) 方法返回false,则x、y这两个对象的hashCode可以相等也可以不等。

默认的hashCode是将内存地址转换为的hash值,重写过后就是自定义的计算方式;

3equals()方法

public boolean equals(Object obj):用于比较当前对象与目标对象是否相等,默认是比较引用是否指向同一对象。为public方法,子类可重写。

public class Object{
    
    
    public boolean equals(Object obj) {
    
    
        return (this == obj);
    }
}

为什么需要重写equals方法?

因为如果不重写equals方法,当将自定义对象放到map或者set中时;如果这时两个对象的hashCode相同,就会调用equals方法进行比较,这个时候会调用Object中默认的equals方法,而默认的equals方法只是比较了两个对象的引用是否指向了同一个对象,显然大多数时候都不会指向同一个,这样就会将重复对象存入map或者set中。这就 破坏了map与set不能存储重复对象的特性,会造成内存溢出 。

重写equals方法的几条约定:

自反性:即x.equals(x)返回true,x不为null;
对称性:即x.equals(y)与y.equals(x)的结果相同,x与y不为null;
传递性:即x.equals(y)结果为true, y.equals(z)结果为true,则x.equals(z)结果也必须为true;
一致性:即x.equals(y)返回true或false,在未更改equals方法使用的参数条件下,多次调用返回的结果也必须一致。x与y不为null。
如果x不为null, x.equals(null)返回false。

4 clone()方法

1 new 一个对象的过程和 clone 一个对象的过程区别?

过程:
new操作符的本意是分配内存:程序执行 到new操作时,根据new操作符后面的类型分配相应的内存空间。分配完内存之后,再调用构造函数完成对象的初始化,填充对象的各个域;构造方法返回后,一个对象创建完毕,可以把它引用发布到外部,在外部就可以使用这个引用操作这个对象。

clone在第一步和new相似,都是分配内存,调用clone方法时,分配的内存和原对象相同,然后再使用原对象中对应的各个域,填充新对象的域,填充完成后,clone方法返回,一个新的对象被创建,同样可以把这个新对象的引用发布到外部。

区别:
clone()不会调用构造方法,new会调用构造方法。
clone()更快:clone()能快速创建一个已有对象的副本,即创建对象并且将已有对象中所有属性值克隆;new只能在JVM中申请一个空的内存区域,对象的属性值要通过构造方法赋值。

2 clone 对象的使用

public class User implements Cloneable {
    
    
    private String id;
    private String name;

    public User() {
    
    
    }

    public User(String id, String name) {
    
    
        this.id = id;
        this.name = name;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
    
    
        return super.clone();
    }
}

public class Main {
    
    
    public static void main(String[] args) throws CloneNotSupportedException {
    
    
        User user = new User("userId", "userName");
        User userClone = (User) user.clone();
        System.out.println(user);
        System.out.println(userClone);
    }
}
从打印结果可以看出,两个对象的地址是不同的,也就是说创建了新的对象, 而不是把原对象的地址赋给了一个新的引用变量:
User@4554617c
User@74a14482

在这里插入图片描述

3深拷贝和浅拷贝

public class User implements Cloneable {
    
    
    private String id;
    private String name;

    public User() {
    
    
    }

    public User(String id, String name) {
    
    
        this.id = id;
        this.name = name;
    }

    @Override
    protected User clone() throws CloneNotSupportedException {
    
    
        return (User) super.clone();
    }

    public String getId() {
    
    
        return id;
    }

    public String getName() {
    
    
        return name;
    }
}

由于 age 是基本数据类型,那么对它的拷贝没有什么疑议,直接将一个 4 字节的整数值拷贝过来就行。但是 name是 String 类型的, 它只是一个引用, 指向一个真正的 String 对象,那么对它的拷贝有两种方式: 直接将原对象中的 name 的引用值拷贝给新对象的 name 字段, 或者是根据原 User 对象中的 name 指向的字符串对象创建一个新的相同的字符串对象,将这个新字符串对象的引用赋给新拷贝的 User 对象的 name 字段。这两种拷贝方式分别叫做浅拷贝和深拷贝。深拷贝和浅拷贝的原理如下图所示:

在这里插入图片描述
如果两个 Person 对象的 name 的地址值相同, 说明两个对象的 name 都指向同一个String 对象,也就是浅拷贝, 而如果两个对象的 name 的地址值不同, 那么就说明指向不同的 String 对象, 也就是在拷贝 Person 对象的时候, 同时拷贝了 name 引用的 String 对象, 也就是深拷贝。验证代码如下:


public class Main {
    
    
    public static void main(String[] args) throws CloneNotSupportedException {
    
    
        User user = new User("userId", "userName");
        User userClone = user.clone();
        System.out.println(
                user.getId() == userClone.getId()
        );
        System.out.println(
                user.getName() == userClone.getName()
        );
    }
}
true
true

clone 是浅拷贝的

5toString()方法

返回当前对象的字符串表示,可以将其打印方便查看对象的信息,方便记录日志信息提供调试。

6finalize()方法

此方法是在垃圾回收之前,JVM会调用此方法来清理资源。此方法可能会将对象重新置为可达状态,导致JVM无法进行垃圾回收。

finalize()方法具有如下4个特点:

永远不要主动调用某个对象的finalize()方法,该方法由垃圾回收机制自己调用;

finalize()何时被调用,是否被调用具有不确定性;

当JVM执行可恢复对象的finalize()可能会将此对象重新变为可达状态;

当JVM执行finalize()方法时出现异常,垃圾回收机制不会报告异常,程序继续执行。

猜你喜欢

转载自blog.csdn.net/zs18753479279/article/details/120017565