real

Object类及常用方法简介

2018-03-13  本文已影响13人  水欣

Object类是一个特殊的类,是所有类的父类,是java中唯一没有父类的类,如果一个类没有用extends明确指出继承于某个类,那么它默认继承Object类。

1.获取对象信息的方法:toString

public class Student {

    private String name = "Mary";
    private int age = 21;

    public static void main(String[] args) {
        Student student = new Student();

        System.out.println(student.toString());
    }
    
}

输出结果

com.netty.test23.Student@24367013

toString()方法,它用于返回标识对象值的字符串。类名@内存地址
随处可见toString()的主要原因是:只要对象与一个字符串通过操作符“+”连接起来,java编译器就会自动地调用toString方法,以便获得这个对象的字符串描述。

2.equals()

判断两个对象是否相等的方法。可以先判断地址是否相等,再判断值是否相等。自定义对象需要重写该方法,不然该方法就是对比地址是否相等。

 public boolean equals(Object obj) {
        return (this == obj);
    }
public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String) anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                            return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

3.hashCode()

返回当前对象的hash code value,这个类是用来支持一些hash table,例如HashMap。
它的性质是:

  1. 相等(相同)的对象必须具有相等的哈希码(或者散列码)。
    解释:想象一下,如果两个java对象A和B,A和B相等(equals结果为true),但A和B的哈希码不同,则A和B存入HashMap时的哈希码计算得到的HashMap内部数组位置索引可能不同,那么A和B很有可能允许同时存入HashMap,显然相等/相同的元素是不允许同时存入HashMap,HashMap不允许存放重复元素。
  2. 如果两个对象的hashCode相同,他们并不一定相等。
    解释:也就是说,不同对象的HashCode可能相同;假如两个Java对象A和B,A和B不相等(equals结果为false),但A和B的哈希码相等,将A和B都存入HashMap时会发生哈希冲突,也就是A和B存入在HashMap时会发生哈希冲突,也就是A和B存放在HashMap内部数组的位置索引相同,这是HashMap会在该位置建立一个链表,将A和B串起来放在该位置,显然,该情况不违反HashMap的使用原则,是允许的。当然,hash冲突越少越好,尽量采用好的hash算法以避免哈希冲突。
    所以,java对于equals方法和hashCode方法是这样规定的:
1. 如果两个对象相同,那么它们的hashCode值一定要相同;
2. 如果两个对象的hashCode相同,它们并一定相同(这里说的对象相同指的是用equals方法比较)。
3. equals()相等的两个对象,hashCode()一定相等;equals()不相等的两个对象,却并不能证明他们的hashCode()不相等。
换句话说,equals()方法不相等的两个对象,hashcode()有可能相等(我的理解是由于哈希码在生成的时候产生冲突造成的)。反过来,hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。

在object类中,hashcode()方法是本地方法,返回的是对象的地址值,而object类中的equals()方法比较的也是两个对象的地址值,如果equals()相等,说明两个对象地址值也相等,当然hashcode()也就相等了;在String类中,equals()返回的是两个对象内容的比较,当两个对象内容相等时,Hashcode()方法根据String类的重写代码的分析,也可知道hashcode()返回结果也会相等。以此类推,可以知道Integer、Double等封装类中经过重写的equals()和hashcode()方法也同样适合于这个原则。当然没有经过重写的类,在继承了object类的equals()和hashcode()方法后,也会遵守这个原则。

4. clone()

源码

protected native Object clone() throws CloneNotSupportedException;

又源码我们会发现:
第一:Object类的clone()方法是一个native方法,native方法的效率一般来说都是远高于java中的非native方法。这也解释了为什么要用Object中的clone方法而不是先new一个类,然后把原始对象中的信息复制到新对象中,虽然这也实现了clone功能。
第二:Object类中的clone()方法被protected修饰符修饰。这也意味着如果要应用clone()方法,必须继承Object类,在java中所有的类是缺省继承Object类的,也就不用关心这点了。然后重载clone()方法。这一点要考虑的是为了让其他类能调用这个对象类的clone()方法,重载之后要把clone()方法的属性设置为public.
第三:Object.clone()方法返回一个Object对象。我们必须进行强制类型转换才能得到我们需要的类型。

浅层复制与深层复制

浅层复制:被复制的对象的所有成员属性都与原来的对象值相同,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅层复制仅仅复制所考虑的对象,而不复制它引用的对象。

public class ShadowClone implements Cloneable {

    private int a;
    private int[] b;

    public Object clone() {
        ShadowClone sc = null;

        try {
            sc = (ShadowClone) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return sc;
    }

    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }

    public int[] getB() {
        return b;
    }

    public void setB(int[] b) {
        this.b = b;
    }

    public static void main(String[] args) {
        ShadowClone c1 = new ShadowClone();

        c1.setA(100);
        c1.setB(new int[]{1000});

        System.out.println("克隆前c1: a=" + c1.getA() + " b=" + c1.getB()[0]);

        ShadowClone c2 = (ShadowClone) c1.clone();
        c2.setA(50);
        int[] a = c2.getB();
        a[0] = 5;
        c2.setB(a);

        System.out.println("克隆前c1:  a=" + c1.getA() + " b=" + c1.getB()[0]);
        System.out.println("克隆后c2:  a=" + c2.getA() + " b[0]=" + c2.getB()[0]);
    }
}

结果为:

克隆前c1: a=100 b=1000
克隆前c1:  a=100 b=5
克隆后c2:  a=50 b[0]=5

c1和c2的对象模型:


image.png

深层复制:被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那么引用其他对象的变量将指向被复制过的新对象,而不是原有的那些被引用的对象。换言之,深层复制要复制的对象引用的对象都复制一遍。

public class Student implements Cloneable {
    private String name;
    private int age;
    Professor pro;
    public Student(){}
    public Student(String name,int age,Professor pro){
        this.name=name;
        this.age=age;
        this.pro=pro;
    }
    public Object clone(){
        Student o=null;
        try {
            //Object中的clone()识别出你要复制的是哪一个对象。
            o=(Student)super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println(e.toString());
        }
        o.pro=(Professor)pro.clone();
        return o;
    }
    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;
    }
    public Professor getPro() {
        return pro;
    }
    public void setPro(Professor pro) {
        this.pro = pro;
    }
}
class Professor implements Cloneable{
    private String name;
    private int age;
    public Professor(){}
    public Professor(String name,int age){
        this.name=name;
        this.age=age;
    }
    public Object clone(){
        Object o=null;
        try {
            o=super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return o;
    }
    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;
    }
}
上一篇下一篇

猜你喜欢

热点阅读