源码 toString()方法、重点深刨equals()方法详解.

1、JDk类库的根类: object
1.1、这个老祖宗类中的方法我们需要先研究一下,因为这些方法都是所有子类通用的。
    任何一个类默认继承bject,就算没有直接继承,最终也会间接继承。

1.2、object类当中有哪些常用的方法?
    我们去哪里找这些方法呢?

    第一种方法:去源代码当中。(但是这种方式比较麻烦,源代码也比较难)
    第二种方法:去查阅java的类库的帮助文档。

1.3、什么是API? 
    应用程序编程接口。( Application Program Interface )
    整个JDK的类库就是一个javase的API。
    每一个API都会配置一套API帮助文档。
    SUN公司提前写好的这套类库就是API。(一般每一份API都对应一份API帮助文档。)

    目前为止我们只需要知道这几个方法即可:
        protected Object clone()  // 负责对象克隆
        boolean equals(Object obj)  // 判断两个对象是否相等
        int hashCode()   // 获取对象哈希值的一个方法
        String toString()  // 将对象转换成字符串形式
        protected void finalize()  // 垃圾回收器负责调用的方法

 1、关于object类中的toString()方法

关于object类中的tostring()方法
1、源代码长什么样?
public String tostring () {
    return this.getClass ().getName() + "@" + Integer.toHexString(hashCode())} ;
                源代码上tostring()方法的默认实现是:(默认返回结果)
                类名@对象的内存地址转换为十六进制的形式

2、SUN公司设计toString()方法的目的是什么?
tostring()方法的作用是什么?
    tostring()方法的设计目的是:通过调用这个方法可以将一个"java对象"转换成"字符串表示形式"

3、其实SUN公司开发java语言的时候,建议所有的子类都去重写tostring()方法。
tostring()方法应该是一个简洁的、详实的、易阅读的

 1.1 没重写toString()方法的输出结果如下所示:

public class homework01 {public static void main(String[] args) {Time time =new Time(1970,1,1);// 调用object的toString()方法String s =time.toString(); // toString()方法返回一个String类型的结果// Time类没有重写toString()方法的输出结果System.out.println(s); // 输出结果:Time@1b6d3586 //类名@对象内存地址形式// 然而我们希望拿到的结果是具体的日期 而不是一串内存地址// 因此我们需要对object类当中的toString()方法进行重写}}class Time { // 默认继承object类int year;int month;int day;public Time() {}public Time(int year, int month, int day) {this.year = year;this.month = month;this.day = day;}
}

输出结果: 

 1.2 重写toStrng()方法后的输出结果为:

public class homework01 {public static void main(String[] args) {Time time =new Time(1970,1,1);String s =time.toString();System.out.println(s); // 年:1970 月:1 日:1// 重点注意:输出引用的时候,会自动调用该引用的toString()方法// System.out.println(time); // 年:1970 月:1 日:1}
}
class Time { // 默认继承object类int year;int month;int day;public Time() {}public Time(int year, int month, int day) {this.year = year;this.month = month;this.day = day;}// 重写父类object当中的toString()方法// 这个toString()方法怎么写呢?// 当然是返回的结果越简洁可读性越强越好public String toString(){return "年:"+this.year+" 月:"+this.month+" 日:"+this.day;}
}

输出结果为:

2、Object类的equals方法

关于object类中的equals方法
1、equals方法的源代码:
    public boolean equals(object obj){
    return (this == obj);}
    以上这个方法是object类的默认实现。

2、SUN公司设计equals方法的目的是什么?
    以后编程的过程当中,都要通过equals方法来判断两个对象是否相等。
    equals方法是判断两个对象是否相等的。

3、我们需要研究一下object类给的这个默认的equals方法够不够用! ! ! !
    在Object类中的equals方法当中,默认采用的是"=="判断两个java对象
    是否相等。而"=="判断的是两个java对象的内存地址,我们应该判断
    两个java对象的内容是否相等。所以老祖宗的equals方法不够用,
    需要子类重写equals


4、判断两个java对象(2008,8,8)是否相等,不能使用"==",因为"=="比较的是两个
对象的内存地址。

 当我们默认继承Object类的equals方法时:(不够用 需要我们重写修改)

public class homework01 {public static void main(String[] args) {// 判断两个基本数据类型的数据是否相等直接使用”==“就行int a =100;int b =100;// 这个”==“是判断a中保存的100和b中保存的100是否相等System.out.println(a==b); // true// 判断两个java对象是否相等,我们该怎么办呢? 能直接(对象 == 对象) 吗?// 创建一个日期对象是:2008年8月8日Time time =new Time(2008,8,8); // 这个对象内存地址为0x1234// 再创建一个日期对象是:2008年8月8日Time time1 =new Time(2008,8,8); // 这个对象内存地址为0x3698// 测试以下,比较两个对象是否相等 能不能使用”==“ ?// 测试结果:这里的”==“判断的是:time中保存的对象内存地址和time1中保存的对象内存地址是否相等// 判断的不是time、time1对象的(2008,8,8)!boolean b1 =time.equals(time1);System.out.println(b1); // false 输出结果是false表示比较的是对象内存地址}
}class Time { // 默认继承object类int year;int month;int day;public Time() {}public Time(int year, int month, int day) {this.year = year;this.month = month;this.day = day;}// 默认继承父类的equals方法(没修改返回结果前 可以省略不写)// Object的equals方法不够用(因为return (this == obj); 比较的还是两个对象的内存地址)public boolean equals(Object obj){ // Object obj =new Time(2008,8,8) [内存地址]; 多态return (this == obj); // this指向time的对象 因为是time调用equals方法}}

运行结果:

 当我们对父类object的equals()方法进行重写后:(能完成判断两个对象是否相同的需求)

public class homework01 {public static void main(String[] args) {Time time =new Time(2008,8,8);Time time1 =new Time(2008,8,8);// time1 =null; boolean b =time.equals(time1); 传进来的为null时System.out.println(b);}
}class Time{private int year;private int day;private int month;public Time() {}public Time(int year, int day, int month) {this.year = year;this.day = day;this.month = month;}public int getYear() {return year;}public void setYear(int year) {this.year = year;}public int getDay() {return day;}public void setDay(int day) {this.day = day;}public int getMonth() {return month;}public void setMonth(int month) {this.month = month;}// 由上次分析可知父类Object的equals方法不够用 我们可以重写以下public boolean equals(Object obj){  // Object obj =new Time();// 当年相同,月相同,日相同,表示两个日期相同,两个对象相同// 获取第一个日期time的年月日int year1 =this.year; // time调用的equals方法 所以this指向time对象int month1 =this.month;int day1 =this.day;/*// 获取第二个日期time1的年月日// 如下操作会报错 因为传进来的time1类型自动转换成了Object类型// 而Object类当中没有year、month、day属性 所以需要向下转型int year2 =obj.year;int month2 =obj.month;int day2 =obj.day;*/if (obj instanceof Time){ // 当传进来的为null时 null instanceof Time(不指向Time类 所以直接返回false)Time t =(Time)obj;int year2 =t.year;int month2 =t.month;int day2 =t.day;if (year1==year2&&month1==month2&&day1==day2){return true;}}return false; // 传进来的obj为null时直接返回false不进行上面的转型}}

运行结果:

结论: 上述代码先取time的年月日再取time1的年月日,体现出了效率过低

由此对equals()方法进行改良:

public class homework01 {public static void main(String[] args) {Time time =new Time(2008,8,8);Time time1 =new Time(2008,8,8);boolean b =time.equals(time1);System.out.println(b);}
}class Time {int year;int day;int month;public Time() {}public Time(int year, int day, int month) {this.year = year;this.day = day;this.month = month;}/*// 改良equals方法public boolean equals(Object obj){if (obj == null){return false;}if (!(obj instanceof Time)){return false;}// 如果this和obj保存的内存地址相同,那么没必要比较了,说明传进来的对象和调用该equals方法的对象是一个对象if (this == obj){return true; // 直接返回true}// 程序能执行到这里说明什么?// 说明obj不是null,obj是Time类型// 不用再判断obj是否instanceof Time ,因为上面已经判断指向了,所以这里可以直接转型Time time3 =(Time)obj;if (this.day==time3.day && this.month ==time3.month && this.year == time3.year){return true;}return false;}*//*// 再次改良public boolean equals(Object obj) {if (obj == null) {return false;}if (!(obj instanceof Time)) {return false;}// 如果this和obj保存的内存地址相同,那么没必要比较了,说明传进来的对象和调用该equals方法的对象是一个对象if (this == obj) {return true; // 直接返回true}// 程序能执行到这里说明什么?// 说明obj不是null,obj是Time类型// 不用再判断obj是否instanceof Time ,因为上面已经判断指向了,所以这里可以直接转型Time time3 = (Time) obj;return this.day == time3.day && this.month == time3.month && this.year == time3.year;// 因为此处有运算符&& 所以当day,month,year条件成立时直接返回true 不成立返回false}*/// 还可以再次改良public boolean equals(Object obj){if (obj == null || !(obj instanceof Time)){return false;}// 如果this和obj保存的内存地址相同,那么没必要比较了,说明传进来的对象和调用该equals方法的对象是一个对象if (this == obj){return true; // 直接返回true}// 程序能执行到这里说明什么?// 说明obj不是null,obj是Time类型// 不用再判断obj是否instanceof Time ,因为上面已经判断指向了,所以这里可以直接转型Time time3 =(Time)obj;if (this.day==time3.day && this.month ==time3.month && this.year == time3.year){return true;}return false;
}}

3、java语言当中的字符串String(String其实也是一个类)有没有重写toString()方法,有没有重写equals方法

总结:
    1、String类已经重写了equals方法,比较两个字符串不能使用==,必须使用equals方法
    equals是通用的
    2、String类已经重写了toString方法

大结论:
    java中基本数据类型比较是否相等时,使用==
    java中所有的引用数据类型统一使用equals方法来判断是否相等

 代码演示:

public class homework01 {public static void main(String[] args) {// 大部分情况下,采用这样的方式创建字符串对象String s1 ="123";String s2 ="hello";// 实际上String也是一个类,不属于基本数据类型(属于:引用数据类型)// 既然String是一个类,那么一定有构造方法(所以我们也可以进行传参的方式进行赋值)// 下面的操作和上面其实一样String s3 =new String("test1");String s4 =new String("test1");// new 两次,两个对象的内存地址,s3保存的内存地址和s4保存的内存地址不同// == 判断的是内存地址,不是对象内容System.out.println(s3 ==s4); //false 说明判断的是对象的内存地址// 那么判断内容是否相等我们需要重写equals方法// 由下的操作可以得知String已经重写了equals方法 // s3直接调用自己重写的equals方法System.out.println(s3.equals(s4)); //true// 判断String有没有重写toString方法String s5 =new String("junker");// 如果String没有重写toString()方法,输出的结果为:类名@对象内存地址形式// 由下面的输出结果可知:String重写了toString方法System.out.println(s5.toString()); //junker}
}

eg: 重写引用数据类型属性的equals方法案例:

public class homework01 {public static void main(String[] args) {Student student =new Student(1,"bj");Student student1 =new Student(1,"bj");boolean b =student.equals(student1);System.out.println(b);}
}class Student{// 学号int no; // 基本数据类型(比较的时候用==)// 所在学校String school;  // 引用数据类型(比较的时候使用equals方法)public Student(int no) {this.no = no;}public Student(int no, String school) {this.no = no;this.school = school;}// 重写toString方法public String toString() {return "学号:"+this.no+" 所在学校:"+this.school;}// 重写equals方法// 需求: 当一个学生的学号相等,并且学校相等时,表示同一个学生public boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student s =(Student)o;return this.no==s.no && this.school.equals(s.school);// this.school 表示的是student对象的school(当前对象)// student.equals(student1)传过来的student1 的school 是String[引用数据类型]// 又因为school是String类型,String本身也是一个类 引用数据类型比较必须用equals方法进行比较// String类当中已经重写了equals和toString方法了 所以可以直接比较两个school是否相同}}

输出结果:

 equals方法深层次刨析:【重点理解】

import java.util.Objects;public class homework01 {public static void main(String[] args) {// Address address =new Address("北京","第六大街","11111");User user =new User("jun",new Address("北京","第六大街","11111"));User user1 =new User("jun",new Address("北京","第六大街","11111"));System.out.println(user.equals(user1));}
}class User{// 用户名String name; // 引用数据类型// 用户地址Address addr; // 引用数据类型public User(String name) {this.name = name;}public User(String name, Address addr) {this.name = name;this.addr = addr;}// 重写// 重写规则:当一个用户的用户名和家庭住址都相同,表示同一个用户@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;User user = (User) o;return this.name.equals(user.name) && this.addr.equals(user.addr);// this.addr 指的是 Address类 但下面的Address类当中没有重写equals 所以还是false 所以要对Address类重写方法// 这里用this.name.equals(user.name)而不是this.name ==user.name的原因是:name是String类型// String类型是引用数据类型 是一个SUN公司写的类, 里面重写好了equals和toString方法// 所以this.name当前对象可以直接调用String类中的equals方法进行两个name的判断// 但是Address也是引用数据类型,(不过是我们自己写的一个类) 这个类也默认继承了Object类 也默认继承了Object类中的方法// 当中的equals方法 但是没有重写 返回的结果还是两个对象的内存地址而不是两个对象的内容 所以结果还是false// 所以 && this.addr.equals(user.addr) 为 false// 所以我们需要对Address类当中的equals方法进行重写}@Overridepublic int hashCode() {return Objects.hash(name, addr);}
}class Address{String city;String street;String zipcode;public Address(String city) {this.city = city;}public Address(String city, String street, String zipcode) {this.city = city;this.street = street;this.zipcode = zipcode;}// 注意:这里并没有重写equals方法// 这里的equals方法判断的是:Address对象和Address对象内容是否相等// new Address("北京","第六大街","11111")public boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Address address = (Address) o;return this.city.equals(address.city)&&this.street.equals(address.street)&&this.zipcode.equals(address.zipcode);}
}

运行结果:


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部