【JAVASE系列】09_toString和equals和内部类


==是关系运算符

一、toString

1、源代码上toString()方法的默认实现:

  • 类名@对象的内存地址转换为十六进制的形式

2、toString方法的作用:

  • 通过调用这个方法可以将一个java对象转换成字符串表示形式
  • 建议所有的子类都重写toString()方法
  • 输出引用的时候,会自动调用toString方法
public class Test05 {
    public static void main(String[] args) {
        MyTime t=new MyTime(1970,1,1);
        //MyTime类重写toString()方法之前,输出的结果为:Day08.MyTime@5594a1b5
        String s1=t.toString();
        System.out.println(s1);
        System.out.println(t.toString());
        //注意:输出引用的时候,会自动调用toString方法
        System.out.println(t);
    }
}
class MyTime{
    private int year;
    private int month;
    private int day;
    public MyTime(){

    }

    public MyTime(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }
    //重写toString方法,为了能够打印出的是日期而非内存地址
    @Override
    public String toString() {
        return this.year+"年"+this.month+"月"+this.day+"日";
    }
}

在这里插入图片描述
在这里插入图片描述

二、equals

1、equals源代码,默认实现:

public boolean equals(Object obj){
    return (this==obj);
}

2、equals的作用:通过equals来判断两个对象是否相等。

  • 判断两个基本数据类型的数据是否相等就直接使用“==”即可。双等号比较的是值。
  • 当使用“==”来比较两个对象是否相等的时候,比较的是对象内存地址是否相等。因此双等号无法比较两个对象是否相等。我们要比较的是两个对象的内容是否相等。
  • 因此我们需要重写equals方法。

在这里插入图片描述

public class Test06 {
    public static void main(String[] args) {
        int a = 10;
        int b = 10;
        System.out.println(a == b);

        MyTime t1=new MyTime(2022,7,1);
        MyTime t2=new MyTime(2022,7,1);
        System.out.println(t1==t2);

        boolean flag=t1.equals(t2);
        System.out.println(flag);
        
        MyTime t3=new MyTime(2022,7,2);
        boolean flag1=t1.equals(t3);
        System.out.println(flag1);      
        
        MyTime t4=null;
        System.out.println(t1.equals(t4));

    }
}

class MyTime{
    private int year;
    private int month;
    private int day;
    public MyTime(){

    }

    public MyTime(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }
    //重写toString方法,为了能够打印出的是日期而非内存地址
    @Override
    public String toString() {
        return this.year+"年"+this.month+"月"+this.day+"日";
    }

    //重写Object类的equals方法
    //比较两个类的年月日
    public boolean equals(Object obj){
        //获取第一个类的年月日
        int year1=this.year;
        int month1=this.month;
        int day1=this.day;
        //获取第二个类的年月日
        if(obj instanceof MyTime){
            MyTime t=(MyTime) obj;
            int year2=t.year;
            int month2=t.month;
            int day2=t.day;

            if(year1==year2 || month1==month2 || day1==day2){
                return true;
            }
        }
        return false;
    }
}

上面的代码可以正常比较对象,null也行,但是效果过低,改进方法如下:

修改之后的equals方法:

    public boolean equals(Object obj){
        if(obj==null){
            return false;
        }//空指针直接返回
        if(!(obj instanceof MyTime)){
            return false;
        }//如果obj不是一个MyTime,就没有必要比较了,直接返回false
        if(this==obj){
            return true;
        }//如果两者内存相同,则直接返回
        //内存地址相同的时候指向的堆内存的对象一定是同一个
        //如果程序执行到此处,则说明obj不是null,obj是MyTime类型
        MyTime t=(MyTime)obj;//直接向下转型
        return this.year==t.year && this.day==t.day && this.month==t.month)
    }

三、String对toString和equals的重写

  • 比较两个字符串不能使用双等号,要使用equals方法。
public class Test07 {
    public static void main(String[] args) {
        //大部分情况下,采用这样的方式创建字符串对象
        String s1="hello";
        String s2="abc";
        //实际上String也是一个类,不属于基本数据类型
        //既然String是一个类,则一定存在构造方法
        String s3=new String("Test1");
        String s4=new String("Test1");
        System.out.println(s3==s4);
        //new了两次,两个对象内存地址,s3保存的内存地址和s4的不同。
        //因此比较两个字符串不能使用双等号。需要使用equals方法。
        //String类已经重写了equals方法。
        System.out.println(s3.equals(s4));

        //如果String没有重写toString方法,则输出的结果含有16进制的地址
        String x=new String("wenxin");
        System.out.println(x.toString());
        //由最后的结果可以得知String有重写toString方法
    }
}

总结:

1、java中的基本数据类型使用“==”来判断是否相等。

2、java中的引用数据类型使用equals方法来判断是否相等。

String对toString和equals的重写:

public class Test08 {
    public static void main(String[] args) {
        Student s1=new Student(111,"北京二中");
        Student s2=new Student(111,"北京二中");
        System.out.println(s1==s2);
        System.out.println(s1.equals(s2));
        
        Student s3=new Student(222,new String("北京二中"));
        Student s4=new Student(222,new String("北京二中"));
        System.out.println(s3==s4);
        System.out.println(s3.equals(s4));

    }


}

class Student{
    int no;
    String school;
    public Student(){};
    public Student(int no,String school){
        this.no=no;
        this.school=school;
    }
    //重写toString方法
    public String toString(){
        return "学号:"+no+",所在学校:"+school;
    }
    //重写equals方法
    //需求:当一个学生的学号相等,并且学校相同的时候,表示同一个学生
    public boolean equals(Object o){
        if(o==null || !(o instanceof Student)){
            return false;
        }
        if(this==o){
            return true;
        }
        Student s= (Student) o;
        if(this.school.equals(s.school) && this.no==s.no){
            return true;
        }
         return false;
    }
}

四、finalize方法

1、在Object当中的源码:

protected void finalize() throws Throwable{}

2、finalize()方法只有一个方法体,里面没有代码,而且是protected修饰的。

3、finalize()方法执行的时机:

  • 当一个java对象即将被垃圾回收器回收的时候,垃圾回收器负责调用
  • finalize()是为程序员准备的一个时机,即垃圾销毁时机。如果希望在对象销毁时机执行一段代码的话,就要写到finalize当中。
    4、重写finalize方法:
public class Test09 {
    public static void main(String[] args) {
        Person p=new Person();
    }
}

class Person{
    //重写finalize方法
    protected void finalize() throws Throwable{
        System.out.println("即将被销毁!");
    }
}

在这里插入图片描述

五、hascode方法

  • 这个方法不是抽象方法,带有native关键字,底层调用C++程序
  • hashCode()方法返回的是哈希码:
    • 实际上就是一个java对象的内存地址,经过哈希算法得到的一个值。
    • 所以hashCode()方法的执行结果可以等同于一个java对象的内存地址。
public class Test09 {
    public static void main(String[] args) {
        Object o=new Object();
        int hashcodeValue=o.hashCode();
        System.out.println(hashcodeValue);
    }
}

在这里插入图片描述

六、匿名内部类

1、内部类:在类的内部又定义了一个新的类。

2、内部类的分类:

  • 静态内部类:类似于静态变量
  • 实例内部类:类似于实例变量
  • 局部内部类:类似于局部变量
class T1{
    
    //该类在类的内部,所以称为内部类
    //由于前面有static,所以是静态内部类
    static class Inner{
    }
    //该类在类的内部,所以称为内部类
    //由于没有static修饰,因此称为实例内部类
    class Inner2{
    }
    
    public void doSome{
        int i=100;
        //该类在类的内部,所以称为内部类
        //该类在方法的内部,因此称为局部内部类,只在这个方法当中起作用
        class Inner3{
        }
    }
}

3、使用内部类编写的代码,可读性差,尽量不要使用。

4、匿名内部类是局部内部类的一种。因为这个类没有名字,因此叫匿名内部类。

public class Test10 {
    public static void main(String[] args) {
        //方法一:写一个接口的实现类Com
        MyMath1 m=new MyMath1();
        m.sum(new Com(),100,200);

        //方法二:使用匿名内部类,这样就不需要写一个接口的实现类了,直接在此处实现接口的抽象方法即可
        MyMath1 mm=new MyMath1();
        mm.sum(new Com(){
            public int sum(int x,int y){
                return x+y;
            }
        },100,200);
    }
}

//负责计算的接口
interface Computer{
    int sum(int a,int b);
}
//实现接口的类
class Com implements Computer{
    public int sum(int a,int b){
        return a+b;
    }
}
class MyMath1{
    public void sum(Computer c,int x,int y){
        int r=c.sum(x,y);
        System.out.println(x+"+"+y+"="+r);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

温欣2030

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值