Java——Object类

Object类

类 Object 是类层次结构的根类。每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。

Object类的通用方法

在这里插入图片描述

1、toString方法

在这里插入图片描述

public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

一个简单的例子

public class Person {
    private String name;
    private int age;
    public Person() {
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}


/*
            Person类默认继承了Object类,所以可以使用其中的toString()方法
            String toString()   返回该对象的字符串表示。
         */
        Person p = new Person("张三", 18);
        System.out.println(p.toString()); //object.demo01.Person@1b6d3586

也就是说在输出这个Person对象的时候,默认输出的是一个对象在堆内存上的地址值(也就是调用了Object类下面的toString()方法,如上上图所示的类的全限定名@十六进制哈希值字符串),如果要输出对象的内容必须覆盖重写toSting()方法。

/*
        直接打印对象的地址值没有意义,所以我们要重写下toString方法,打印对象的属性(name,age)
     */
    @Override
    public String toString() {
        return "Person{name = " + name + ",age = " + age + "}";
    }

在这里插入图片描述

2、equals方法

在这里插入图片描述

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

等价关系
两个对象等价需要满足如下条件

  • 自反性
x.equals(x);//true
  • 对称性
x.equals(y) == y.equals(x);//true
  • 传递性
if(x.equals(y) && y.equals(z))
	x.equals(z);//true
  • 一致性
x.equlas(y) == x.equals(y);//true
  • 与null的比较
x.equals(null);//false

equals来比较对象内容是否相等
直接调用equals方法来比较的是两个对象的地址值,如果需要比较两个对象的内容,则需要重写equals方法。

public class Person {
    private String name;
    private int age;
}

/*
            Person类默认继承了Object类,所以可以使用Object类的equals()方法
            boolean equals(Object obj) 指示其他某个对象是否与此对象“相等”。
         */
        Person p1 = new Person("迪丽热巴", 18);
        Person p2 = new Person("古力娜扎", 19);
        Person p3 = new Person("迪丽热巴", 18);
        System.out.println(p1.equals(p3));//false
/*
        Object类的equals方法,默认比较的是两个对象的地址值,没有意义
        所以我们要重写equals方法,比较两个对象的属性(name,age)
        问题:
            隐含一个多态(弊端:无法使用子类特有的内容)
            Object obj = p1 = new Person("迪丽热巴",18);
            解决:可以向下转型
     */
    @Override
    public boolean equals(Object obj) {
        //增加一个判断,传递的参数obj如果是this本身,直接返回true,提高程序效率
        if (obj == this) return true;
        //增加一个判断,如果是空,直接返回false 提高程序的效率
        if (obj == null) return false;
        if (obj instanceof Person) {
            //向下转型
            Person p = (Person) obj;
            //比较两个对象的属性
            return this.name.equals(p.name) && this.age == p.age;
        }
        return false;
    }


Person p1 = new Person("迪丽热巴", 18);
        Person p2 = new Person("古力娜扎", 19);
        Person p3 = new Person("迪丽热巴", 18);
        System.out.println(p1.equals(p3));//true
3、hashCode方法

hashCode()返回哈希值,而equals是用来判断两个对象是否等价。等价的两个对象散列值一定相等,但是散列值相同的两个对象不一定相等,这是因为哈希值具有随机性,两个值不同的对象可能计算出相同的哈希值。

所以在覆盖重写equals方法的同时,应当要也要覆盖重写hashCode方法,保证两个对象哈希值也相等。

HashSet和HashMap等集合类使用了hashCode()方法来计算对象应该存储的位置,因此要将对象添加到这些集合类中,需要让对应的类实现hashCode()方法

如下面的代码,EqualsExample没有实现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

理想的哈希函数应当具有均匀性,即不相等的对象应当均匀分布到所有可能的哈希值上。这就要求了哈希函数要把所有域的值都考虑进来。可以将每个域都当成 R 进制的某一位,然后组成一个 R 进制的整数。

R 一般取 31,因为它是一个奇素数,如果是偶数的话,当出现乘法溢出,信息就会丢失,因为与 2 相乘相当于向左移一位,最左边的位丢失。并且一个数与 31 相乘可以转换成移位和减法:31*x == (x<<5)-x,编译器会自动进行这个优化。

@Override
public int hashCode() {
    int result = 17;
    result = 31 * result + x;
    result = 31 * result + y;
    result = 31 * result + z;
    return result;
}
4、clone方法
1、cloneable

clone()是Object类中用protected修饰的方法,所以如果一个类不显示的去覆盖重写这个方法,其他类就无法调用该类实例的clone()方法

public class CloneExample {

    private int a;
    private int b;

    @Override
    protected CloneExample clone() throws CloneNotSupportedException {
        return (CloneExample) super.clone();
    }
}
CloneExample c1 = new CloneExample();
        //c1.clone(); 'clone()' has protected access in 'java.lang.Object'

        try {
            CloneExample clone = c1.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }

会抛出CloneNotSupportedException异常,这是因为CloneExample没有实现Cloneable接口。

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

public class CloneExample implements Cloneable{

    private int a;
    private int b;

    @Override
    protected CloneExample clone() throws CloneNotSupportedException {
        return (CloneExample) super.clone();
    }
}
2、浅拷贝

拷贝对象和原始对象的引用类型引用同一个对象

/*
    浅拷贝:拷贝对象和原始对象的引用类型引用同一个对象
 */
public class ShallowCloneExample implements Cloneable {
    private int[] arr;

    public ShallowCloneExample() {
        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 ShallowCloneExample clone() throws CloneNotSupportedException {
        return (ShallowCloneExample) super.clone();
    }
}
ShallowCloneExample e1 = new ShallowCloneExample();
        ShallowCloneExample e2 = null;
        try {
            e2 = e1.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        e1.set(2,222);
        System.out.println(e2.get(2));//222
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;
    }
}
DeepCloneExample e3 = new DeepCloneExample();
        DeepCloneExample e4 = null;
        try {
            e4 = e3.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        e3.set(2,222);
        System.out.println(e4.get(2));//2
4、clone()的替代方案

使用clone()方法来拷贝一个对象既复杂又有风险,他会抛出异常,而且还需要类型转换。Effective Java书上讲到,最好不要去使用clone(0,可以使用拷贝构造函数或者拷贝工厂来拷贝一个对象。

public class CloneConstructorExample {

    private int[] arr;

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

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

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

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

    public static void main(String[] args) {
        CloneConstructorExample e1 = new CloneConstructorExample();
        CloneConstructorExample e2 = new CloneConstructorExample(e1);
        e1.set(2,222);
        System.out.println(e2.get(2));//2
    }
}
5、好文推荐

https://www.cnblogs.com/ysocean/p/8482979.html#_label5_0

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值