• 【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+"日";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

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

    二、equals

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

    public boolean equals(Object obj){
        return (this==obj);
    }
    
    • 1
    • 2
    • 3

    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    上面的代码可以正常比较对象,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)
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    三、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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    总结:

    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    四、finalize方法

    1、在Object当中的源码:

    protected void finalize() throws Throwable{}
    
    • 1

    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("即将被销毁!");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    五、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
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    六、匿名内部类

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

    2、内部类的分类:

    • 静态内部类:类似于静态变量
    • 实例内部类:类似于实例变量
    • 局部内部类:类似于局部变量
    class T1{
        
        //该类在类的内部,所以称为内部类
        //由于前面有static,所以是静态内部类
        static class Inner{
        }
        //该类在类的内部,所以称为内部类
        //由于没有static修饰,因此称为实例内部类
        class Inner2{
        }
        
        public void doSome{
            int i=100;
            //该类在类的内部,所以称为内部类
            //该类在方法的内部,因此称为局部内部类,只在这个方法当中起作用
            class Inner3{
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
  • 相关阅读:
    Visual Studio ERROR : LNK2001 和LNK2019
    bean的生命周期
    【目标检测评价指标】
    辉芒微IO单片机FT60F024-RB
    12月3日下午:thinkphp框架中的视图以及模型剩余部分
    JPBC的使用
    Redis 技术整理
    第十二章 Python正则表达式
    JavaSE笔记(三)重制版
    【响应式布局】使用 flexbox 实现简单响应式布局
  • 原文地址:https://blog.csdn.net/wxfighting/article/details/125553941