Java Object总结

Object通用方法

public final native Class<?> getClass()

public native int hashCode()

public boolean equals(Object obj)

protected native Object clone() throws CloneNotSupportedException

public String toString()

public final native void notify()

public final native void notifyAll()

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

protected void finalize() throws Throwable {}

一: equals()
Object中默认是==,正常业务中会重写。
1、自反性
2、对称性
3、传递性
4、一致性

//自反性
x.equals(x); // true 

//对称性
x.equals(y) == y.equals(x); // true 

//传递性
if (x.equals(y) && y.equals(z))
    x.equals(z); // true 
    
//一致性
x.equals(y) == x.equals(y); // true 

//对任何不是 null 的对象 x 调用 x.equals(null) 结果都为 false
x.equals(null); // false;

**二: equals() 与 == **
1、对于基本类型,== 判断两个值是否相等(基本类型没有 equals() 方法)
2、对于引用类型,== 判断两个变量是否引用同一个对象(内存地址是否相同),而 equals() 判断引用的对象是否等价。
3、==对比的是栈中的值,基本类型是变量值、引用类型是堆中内存对象的地址

总结:
所有比较是否相等时,都是用equals 并且在对常量相比较时,把常量写在前面,因为使用object的
equals object可能为null 则空指针
在阿里的代码规范中只使用equals ,阿里插件默认会识别,并可以快速修改,推荐安装阿里插件来排
查老代码使用“==”,替换成equals

equals()源码分析如下:

public class EqualExample {
    private int x;
    private int y;
    private int z;

    public EqualExample(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    @Override
    public boolean equals(Object o) {

       //1、检查是否为同一个对象的引用,如果是直接返回 true
        if (this == o) return true;
       //2、检查是否是同一个类型,如果不是,直接返回 false
        if (o == null || getClass() != o.getClass()) return false;
       //3、将 Object 对象进行转型
        EqualExample that = (EqualExample) o;
       //4、判断每个关键域是否相等
        if (x != that.x) return false;
        if (y != that.y) return false;
        return z == that.z;
    }
}

三:hashCode()
hashCode() 返回散列值( native int),其作用是确定该对象在哈希表中的索引位置,可以根据K快速查询对应的V,而 equals() 是用来判断两个对象是否等价。等价的两个对象散列值hashCode一定相同,但是散列值相同的两个对象不一定等价。

为什么要有hashCode()?

以HashSet为例,在对象加入add时,会先计算对象的hashCode,来确定该对象在哈希表中的索引位置,如果该位置有值,会调用equals()来检查两个对象是否真的相同,如果相同则不会加入成功,如果不同就会重新hashCode散列到其他位置,这样大大减少了equals()的次数,相应到就提升了执行到效率。

在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证等价的两个对象散列值也相等。

解释一下为什么“在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法”?

EqualExample e1 = new EqualExample(1, 1, 1);
EqualExample e2 = new EqualExample(1, 1, 1);
System.out.println(e1.equals(e2)); // true
HashSet<EqualExample> set = new HashSet<>();
set.add(e1);
set.add(e2);
System.out.println(set.size());   // 2

代码中建了两个等价的对象,并将它们添加到 HashSet 中。我们希望将这两个对象当成一样的,只在集合中添加一个对象,但是因为 EqualExample 没有实现 hasCode() 方法,由于HashSet 底层是HashMap因此这两个对象的散列值hasCode是不同的,最终导致集合添加了两个等价的对象。

四:toString()
默认返回 ToStringExample@4554617c 这种形式,其中 @ 后面的数值为散列码的无符号十六进制表示。可以按照自己的业务要求重写toString()

五:clone()

1、clone() 是 Object 的 protected 方法,它不是 public,一个类不显式去重写 clone(),其它类就不能直接去调用该类实例的 clone() 方法,否则抛出了 CloneNotSupportedException。

public class CloneExample implements Cloneable {
    private int a;
    private int b;

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

应该注意的是,clone() 方法并不是 Cloneable 接口的方法,而是 Object 的一个 protected 方法。Cloneable 接口只是规定,如果一个类没有实现 Cloneable 接口又调用了 clone() 方法,就会抛出 CloneNotSupportedException。

2、浅拷贝
super.clone() 即可,拷贝对象和原始对象的引用类型引用同一个对象。

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

3、深拷贝
拷贝对象和原始对象的引用类型引用不同对象。

/***
**手动赋值,效率高,但代码过于啰嗦
**/
public class DeepCloneExample implements Cloneable {
    private int[] arr;

    public DeepCloneExample() {
        arr = new int[10];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = i;
        }
    }

    public void set(int index, int value) {
        arr[index] = value;
    }

    public int get(int index) {
        return arr[index];
    }

    @Override
    protected DeepCloneExample clone() throws CloneNotSupportedException {
        DeepCloneExample result = (DeepCloneExample) super.clone();
        result.arr = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            result.arr[i] = arr[i];
        }
        return result;
    }
}

4、 clone() 的替代方案

  • 手动赋值,效率高,但代码过于啰嗦。
  • 序列化与反序列化,使用SerializationUtils的clone(Object obj)方法,要求拷贝的对象实现了Serializable,Map不行,使用HashMap即可。
 this.para = (Map<String, Object>) SerializationUtils.clone((HashMap<String, Object>)po.getPara());
  • 用fastjson从Object转成json,然后转回object,本质上是反射:
    private Object deepCopyByJson(Object obj) {
     String json = JSON.toJSONString(obj);
     return JSON.parseObject(json, Object.class);
 }

5、建对象的几种方式

  • 使用new关键字 → 调用了构造函数
  • 使用Class类的newInstance方法 → 调用了构造函数
  • 使用Constructor类的newInstance方法 → 调用了构造函数
  • 使用clone方法 → 没有调用构造函数
  • 使用反序列化 → 没有调用构造函数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值