Object类中的方法

来源:互联网 发布:淘宝总公司投诉电话 编辑:程序博客网 时间:2024/05/01 06:52

为了便于验证,定义一个User实体类如下:

public class User {    private int id;    private String name;    private Integer age;    private Date birthday;    public User(int id, String name, Integer age, Date birthday) {        super();        this.id = id;        this.name = name;        this.age = age.intValue();        this.birthday = birthday;    }    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public Integer getAge() {        return age;    }    public void setAge(Integer age) {        this.age = age;    }    public Date getBirthday() {        return birthday;    }    public void setBirthday(Date birthday) {        this.birthday = birthday;    }    @Override    public String toString() {        return "User [id=" + id + ", name=" + name + ", age=" + age                + ", birthday=" + birthday.getTime() + "]";    }}

1.equals()
在Object类中定义的equals方法,其含义在于判断两个对象的地址是否相同,即判断两个对象是否为同一对象。这时,equals() 等价于”==”。
由于所有的类都继承自Object,所以如果自己定义的类未重写(override)equals方法,则equals判断两个对象是否为同一对象;
如果重写了equals方法,则equals的判断逻辑根据方法本身的实现。通常做法是根据业务逻辑,判断对象的属性值是否相等。

    public static void main(String[] args) {        User user1 = new User(1,"John",24,new Date());        User user2 = new User(1,"John",24,new Date());        System.out.println(user1.equals(user2)); //out:false        System.out.println(user1.equals(user1)); //out:true        System.out.println(user1 == user2); //out:false        System.out.println(user1 == user1); //out:true    }

覆盖equals方法:

    @Override    public boolean equals(Object obj) {        //非空对象不可与null值相等        if(obj == null) return false;        //同一对象一定相等        if(this == obj) return true;        //类型不同的两个对象一定不相等        if(this.getClass() != obj.getClass()) return false;        //当且仅当三个属性都相等时,两个对象相等        User person = (User)obj;          return id==person.id && name.equals(person.name) && age.intValue()==person.age.intValue();      }

覆盖equals方法后,user1与user2相等:

    public static void main(String[] args) {        User user1 = new User(1,"John",24);        User user2 = new User(1,"John",24);        System.out.println(user1.equals(user2)); //out:true        System.out.println(user1.equals(user1)); //out:true        System.out.println(user1 == user2); //out:false        System.out.println(user1 == user1); //out:true    }

2.hashCode()
hashCode方法的返回值为int,用来确定一个对象在散列表中的索引位置。该方法在创建当前类的散列集(HashMap, HashSet, Hashtable)时才有意义,其它情况没有意义。

– equals为true的两个对象,hashCode一定相同;
– hashCode相同的两个对象,equals不一定为true(哈希冲突)
– 在使用散列集时,如果重写了equals方法,则一定要重写为hashCode方法,否则equals方法无效。

重写hashCode方法:

@Overridepublic int hashCode() {    final int prime = 31;    int result = 1;    result = prime * result + ((age == null) ? 0 : age.hashCode());    result = prime * result + ((birthday == null) ? 0 : birthday.hashCode());    result = prime * result + id;    result = prime * result + ((name == null) ? 0 : name.hashCode());    return result;}

3.clone()
首先,考虑一下使用“=”赋值运算符的情况。
在Java中的数据类型分为两大类:基本类型和引用类型
基本类型:int, long, float, double, char等。
引用类型:Integer, Long, Float, Double, String等。
将一个基本类型的变量赋值给基本类型的时候,新变量会在堆内存中开辟自己的空间,再把旧变量的值写入。因此新旧变量的内存是各自独立的堆空间,对其中一个变量的值更改不会影响另一个变量的值;
将一个引用类型的变量赋值给引用类型的时候,新变量并不会在堆内存中开辟自己的空间,而是仅仅保存了旧变量引用的堆内存地址,两个变量指向同一块堆内存空间。因此,对一个变量值的更改会影响另一个变量的值。
下边这个简单的程序说明了这一点:

int a = 5;int b = a;a = 10;System.out.println("a="+a+",b="+b);//out:a=10,b=5Integer a1 = 5;Integer b1 = a1;        System.out.println("a1="+a1+",b1="+b1);//out:a1=5,b1=5

由于我们自定义的类都是引用类型的,所以,如果需要使新对象和旧对象拥有相同的值,并且对其中一个对象状态的更改不会影响另一个对象,就需要使用clone()方法。
使用clone方法需要:
1.实现Cloneable接口;(只作为标识)
2.重写Object类的clone方法,并将访问修饰符定义为public。(因为在Object类中的clone方法是protected的,只能在本类中访问)
下面在使User类实现Cloneable接口,并重写clone方法,使用默认的实现:

public class User implements Cloneable
    @Override    public User clone() throws CloneNotSupportedException {        return (User)super.clone();    }

在测试方法里验证clone方法:

User user1 = new User(1,"user1",24, new Date());//浅拷贝User user2 = user1.clone();System.out.println("user1:"+user1);//out:"user1:User [id=1, name=user1, age=24, birthday=1430137523544]"System.out.println("user2:"+user2);//out:"user2:User [id=1, name=user1, age=24, birthday=1430137523544]"user2.setName("user2");user2.setAge(30);System.out.println("user1:"+user1);//out:"user1:User [id=1, name=user1, age=24, birthday=1430137523544]"System.out.println("user2:"+user2);//out:"user2:User [id=1, name=user2, age=30, birthday=1430137523544]"user2.getBirthday().setTime(1430137087450L);System.out.println("user1:"+user1);//out:"user1:User [id=1, name=user1, age=24, birthday=1430137087450]"System.out.println("user2:"+user2);//out:"user2:User [id=1, name=user2, age=30, birthday=1430137087450]"

可以看出在7、8行对新对象String类型和Integer类型进行更改时,并没有影响旧对象该域的值。因为这两种类型都是final类型的,为不可变类型,所以每次赋值都是堆内存中的一个新对象。
而第11行,对Date类型的值做改变的时候,旧对象的值也相应的改变。
由此可见,Object类中clone的默认实现是“浅拷贝”。
浅拷贝的意思是:当拷贝一个类的对象时,对于旧对象中基本类型的域和不可变引用类型(String, Integer等)的域 在堆内存中开辟独立的空间给新对象,而对于可变引用类型(Date, 自定义类型)的域 使新对象共享旧对象该域的堆内存空间。
我们通常需要的是深拷贝,即:所有域都开辟独立于旧对象的堆内存空间,各自的更改不影响对方。
重新定义clone方法,实现深拷贝:

@Overridepublic User clone() throws CloneNotSupportedException {    User cloned = (User)super.clone();    //将所有的可变引用类型的域都clone    cloned.birthday = (Date)birthday.clone();    return cloned;}

运行结果:

User user1 = new User(1,"user1",24, new Date());//深拷贝User user2 = user1.clone();     System.out.println("user1:"+user1);//out:"user1:User [id=1, name=user1, age=24, birthday=1430139233085]"System.out.println("user2:"+user2);//out:"user2:User [id=1, name=user1, age=24, birthday=1430139233085]"user2.setName("user2");user2.setAge(30);System.out.println("user1:"+user1);//out:"user1:User [id=1, name=user1, age=24, birthday=1430139233085]"System.out.println("user2:"+user2);//out:"user2:User [id=1, name=user2, age=30, birthday=1430139233085]"user2.getBirthday().setTime(1430137087450L);System.out.println("user1:"+user1);//out:"user1:User [id=1, name=user1, age=24, birthday=1430139233085]"System.out.println("user2:"+user2);//out:"user2:User [id=1, name=user2, age=30, birthday=1430137087450]"

可见新对象的birthday的改变已不在影响旧对象该域的值

0 0