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;
}
// 重写
// 重写规则:当一个用户的用户名和家庭住址都相同,表示同一个用户
@Override
public 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方法进行重写
}
@Override
public 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);
}
}
运行结果: