Object类中的方法

为了便于验证,定义一个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方法:

@Override
public 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=5
Integer 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方法,实现深拷贝:

@Override
public 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值