05java课堂笔记 - Object类的方法、匿名内部类

p1、关于object类中的toString()方法
1、源代码语句:
    public String toString(){
      return this.getclass().getName() + "@" + Integer.toHexString(hashCode());
    }
  - 方法的默认实现是:类名@对象的内存地址的十六进制形式
2、toString()方法的作用?
  - toString()方法是一个实例方法,将对象转换成字符串,返回一个“以文本方式表示此对象”的字符串
  - toString()方法将一个“java对象”转换成“字符串表示形式”

3、java中所有的类都默认继承object类,object类的toString()方法,作用是输出一些当前对象的信息比如类标记等
  - toString()方法应该是一个简洁的、翔实的、易阅读的方法,建议所有的子类都重写此方法
  - 使用 print(引用名/对象名) 语句直接输出引用时,程序会自动调用该引用的 toString()方法

示例1:toString()的作用

复制代码
public class Test{
    //Test默认继承Object,故本类中有toString()方法
    /*
    public String toString(){
    return getClass().getName() + "@" +Integer.toHexString(hashCode());
  }
    */

    public static void main(String[] args){
        
        //输出的字符串文本可以等同看做对象在堆内存中的内存地址
        Test t = new Test();
        System.out.println(t.toString());  //Test@15db9742
        
        Product pro = new Product();
        System.out.println(pro.toString());  //Product@6d06d69c
        System.out.println(pro);  //Product@6d06d69c 自动调用toString()方法
        
        Persion per = new Persion();
        System.out.println(per.toString());  //[name=AAA, age=22, gender=女]
        System.out.println(per);  //[name=AAA, age=22, gender=女]
    }
}

class Product{
    //默认继承Object
    /*
    public String toString(){
    return getClass().getName() + "@" +Integer.toHexString(hashCode());
  }
    */
}

class Persion {
    String name = "AAA";
    int age = 22;
    String gender = "女";
    
    @Override
    public String toString() {
        return "[name=" + name + ", age=" + age + ", gender=" + gender + "]";
    }
}
View Code
复制代码

示例2:toString方法应用

复制代码
public class Test{
    public static void main(String[] args){
        
        //一个日起对象转换成字符串形式的话,我们可能更希望看到具体的日期信息
        MyTime mt = new MyTime(1970,1,1);
        String s = mt.toString();
        
        //MyTime类重写toString()方法之前
        System.out.println(s);  //MyTime@15db9742
        //MyTime类重写toString()方法之后
        System.out.println(s);  //1970/1/1
        
        System.out.println(mt.toString());  //1970/1/1
        System.out.println(mt);  //1970/1/1  输出引用时则自动调用该引用的toString()方法
    }
}

class MyTime {
    int year;
    int month;
    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 + "日";
        return this.year + "/" + this.month + "/" + this.day;
    }
}
View Code
复制代码

 


 

 

p2、关于object类中的equals()方法
1、equals()方法的源代码:
    public boolean equals(Object obj){
      return (this == obj);
    }
  - 以上是该方法的默认实现:比较两个对象的内存地址是否相等
2、equals()方法的作用?
  - equals()方法是一个实例方法,判断两个对象是否相等

3、equals()方法的默认实现够不够用?
  - 判断两个对象是否相等不能用“==”,因为“==”是基本数据类型的运算符,只能判断两个对象的内存地址是否相等,不能判断两个对象的内容
  - equals()方法默认采用“==”来判断两个java对象是否相等,只能判断两个对象的内存地址,不能判断两个对象的内容,因此这里不能用“==”,equals()方法的默认实现不够用,需要子类重写equals()方法

示例1:如何比较基本型数据、如何比较对象,equals()方法

复制代码
public class Test{
    public static void main(String[] args){
        
        //判断两个基本数据类型的数据是否相等 直接使用“==”
        int a = 100;
        int b = 100;
        //这里“==”判断a中保存的数据和b中保存的数据是否相等
        System.out.println("整数:" + (a == b));  //true
        
        //判断两个字符型数据是否相等
        char c = 'a';
        char d = 'a';
        System.out.println("字符:" + (c == d));  //true
        
        //判断两个字符串数据是否相等
        String e = "abc";
        String f = "abc";
        System.out.println("字符串:" + (e == f));  //true
        
        //判断两个java对象是否相等 如何比较呢?
        MyTime t1 = new MyTime(2008,8,8);  //t1 = 0x1234
        MyTime t2 = new MyTime(2008,8,8);  //t2 = 0x3658
        //"=="只能判断两个对象的内存地址是否相等
        //这里“==”判断的是t1中保存的内存地址和t2中保存的内存地址是否相等
        System.out.println(t1 == t2);  //false
        
        //比较对象的字符串形式会是什么结果呢?
        System.out.println(t1);  //MyTime@15db9742
        System.out.println(t2);  //MyTime@6d06d69c
        System.out.println(t1.toString() == t2.toString());  //false
        
        //重写equals()方法之前,比较的是两个对象的内存地址
        /*
        boolean flag = t1.equals(t2);
        System.out.println(flag);  //false
        */
        
        //重写equals()方法之后,比较的是两个对象的内容
        boolean flag = t1.equals(t2);
        System.out.println(flag);  //true
        
        //再创建一个新日期
        MyTime t3 = new MyTime(2008,8,9);
        System.out.println(t1.equals(t3));  //false
    }
}

class MyTime {
    int year;
    int month;
    int day;
    
    public MyTime(){}
    public MyTime(int year,int month,int day){
        this.year = year;
        this.month = month;
        this.day = day;
    }
    
    //默认的equals()方法
    /*
    public boolean equals(Object obj) {
        return (this == obj);
    }
    */
    
    //重写equals()方法
    //到底该怎么重写?你认为两个对象什么时候表示相等,你就怎么写
    @Override
    public boolean equals(Object obj) {
        //当年相同、月相同、日也相同的时候,表示两个日期相同,两个对象相等
        //获取第一个日期的年月日
        //获取第二个日期的年月日
        //开始比较
        
        //获取第一个日期的年月日
        int year1 = this.year;
        int month1 = this.month;
        int day1 = this.day;
        
        //获取第二个日期的年月日,多态关系,找不到对象,不能直接获取子类对象特有的属性
        /*
        int year2 = obj.year;
        int month2 = obj.month;
        int day2 = obj.day;
        */
        if(obj instanceof MyTime){
            MyTime mytime = (MyTime)obj;
            int year2 = mytime.year;
            int month2 = mytime.month;
            int day2 = mytime.day;
            if(year1 == year2 && month1 == month2 && day1 == day2){
                return true;
            }
        }
        //程序能够执行到此处表示日期不相同对象不相等
        return false;
    }
}
View Code
复制代码

示例2:改良equals()方法

复制代码
public class Test{
    public static void main(String[] args){
        //判断两个java对象是否相等 如何比较呢?
        MyTime t1 = new MyTime(2008,8,8);  //t1 = 0x1234
        MyTime t2 = new MyTime(2008,8,8);  //t2 = 0x3658
        //"=="只能判断两个对象的内存地址是否相等
        //这里“==”判断的是t1中保存的内存地址和t2中保存的内存地址是否相等
        System.out.println(t1 == t2);  //false
        
        //重写equals()方法之后,比较的是两个对象的内容
        System.out.println(t1.equals(t2));  //true
        
        //再创建一个新日期
        MyTime t3 = new MyTime(2008,8,9);
        System.out.println(t1.equals(t3));  //false
        
        //这个程序有bug吗?可以运行,但是效率怎么样?低,如何改造?
        MyTime t4 = null;
        System.out.println(t1.equals(t4));  //false
        
        MyTime t5 = t1;
        System.out.println(t1.equals(t5));  //true
        
        MyTime t6 = new MyTime(2008,8,10);
        System.out.println(t1.equals(t6));  //false
    }
}

class MyTime {
    int year;
    int month;
    int day;
    
    public MyTime(){}
    public MyTime(int year,int month,int day){
        this.year = year;
        this.month = month;
        this.day = day;
    }

    /*
    //改良equals()方法
    @Override
    public boolean equals(Object obj) {
        //如果obj是空,直接返回false
        if(obj == null) 
            return false;
        
        //如果obj不是一个MyTime,没必要比较了,直接返回false
        if(!(obj instanceof MyTime)) 
            return false;
        
        //如果this和obj的内存地址相同,也没必要比较了,直接返回false
        //如果内存地址相同,指向的堆内存的对象肯定是同一个
        if(this == obj) 
            return true;
        
        //程序能够执行到此处,说明obj不是null,obj是一个MyTime类型
        MyTime t = (MyTime)obj;
        if(this.year == t.year && this.month == t.month && this.day == t.day) 
            return true;
        
        //程序能够执行到此处,表示两个对象不相等
        return false;    
    }
    */
    
    //再次精简改良equals()方法
    @Override
    public boolean equals(Object obj) {
        if(obj == null || !(obj instanceof MyTime))
            return false;
        if(this == obj) 
            return true;
        MyTime t = (MyTime)obj;
        return this.year == t.year && this.month == t.month && this.day == t.day;  //返回true或false
    }
}
View Code
复制代码

 


 

p3、java语言当中的字符串String类有没有重写toString()方法,有没有重写equals()方法
总结:
  1、String类已经重写了equals()方法,比较两个String对象时必须使用equals()方法,比较两个字符串也不要使用“==”,equals是通用的
  2、String类已经重写了toString方法
大结论:
1、java中什么类型的数据可以使用“==”判断?
  java中基本数据类型判断是否相等,使用“==”
2、java中什么类型的数据需要使用equals()判断?
  Java中所有的引用数据类型统一使用equals()方法来判断是否相等

示例1:如何比较两个字符串,String类是否重写了equals()方法,是否重写了toString()方法

复制代码
public class Test{
    public static void main(String[] args){
        //大部分情况下再用这样的方式创建字符串对象
        String s1 = "hello";
        String s2 = "abc";
        
        //实际上String也是一个类,不属于基本数据类型
        //既然String是一个类,那么一定存在构造方法
        String s3 = new String("test1");
        String s4 = new String("test1");
        //new两次,就有两个对象内存地址
        System.out.println(s3 == s4);  //false
        
        //比较两个字符串能不能使用"=="?不能,必须调用equals()方法
        //String类已经重写equals()方法了
        System.out.println(s3.equals(s4));  //true
        
        //String类有没有重写toString方法呢?
        String s5 = new String("动力节点");
        //如果String没有重写toString()方法,输出结果应该是:java.lang.String@十六进制地址
        //经测试String类已经重写了toString()方法
        System.out.println(s5.toString());  //动力节点
        System.out.println(s5);  //动力节点
    }
}
View Code
复制代码

示例2:两个String对象进行比较的时候必须使用equals方法

复制代码
public class Test{
    public static void main(String[] args){
        Student s1 = new Student(111,"梁庄六小");
        Student s2 = new Student(111,"梁庄六小");
        System.out.println(s1);  //学号:111,学校名称:梁庄六小
        System.out.println(s2);  //学号:111,学校名称:梁庄六小
        System.out.println(s1 == s2);  //false
        System.out.println(s1.equals(s2));  //true
        
        Student s3 = new Student(222,new String("二实小"));
        Student s4 = new Student(222,new String("二实小"));
        System.out.println(s3);  //学号:111,学校名称:梁庄六小
        System.out.println(s4);  //学号:111,学校名称:梁庄六小
        System.out.println(s3 == s4);  //false
        System.out.println(s3.equals(s4));  //true
    }
}

class Student{
    int no;
    String school;
    
    public Student(){}
    public Student(int no,String school){
        this.no = no;
        this.school = school;
    }
    
    //重写toString()方法
    @Override
    public String toString(){
        return "学号:" + no + ",学校名称:" + school;
    }
    
    //重写equals()方法
    //需求:当一个学生的学号相等、学校相同时,表示同一个学生
    //equals()方法的编写模式是固定的,框架基本一致
    @Override
    public boolean equals(Object obj){
        if(obj == null || !(obj instanceof Student))
            return false;
        if(this == obj)
            return true;
        Student student = (Student)obj;
        /*
        if(this.no == student.no && this.school.equals(student.school))
            return true;
        return false;
        */
        return this.no == student.no && this.school.equals(student.school);
        
        //字符串用“==”比较可以吗?不可以
        //比较String对象时,必须使用equals()方法,否则比较的结果为false
        //return this.no == student.no && this.school == student.school;
    }
}
View Code
复制代码

 

示例3:equals()方法的深层次剖析,equals()重写要彻底

复制代码
public class Test{
    public static void main(String[] args){
        User u1 = new User("zhangsan",new Address("内黄","牡丹街","111111"));
        User u2 = new User("zhangsan",new Address("内黄","牡丹街","111111"));
        System.out.println(u1.equals(u2));  //true,这里调用的是User类的equals()方法
        
        User u3 = new User("zhangsan",new Address("内黄","牡丹街","111112"));
        System.out.println(u1.equals(u3));  //false
    }
}

class User{
    //用户名
    String name;
    //家庭住址
    Address addr;
    
    public User(){}
    public User(String name,Address addr){
        this.name = name;
        this.addr = addr;
    }
    
    //重写equals()方法
    //重写规则:当两个用户名和家庭住址都相同时,表示同一个用户
    //这个equals()判断的是User对象和User对象是否相等
    @Override
    public boolean equals(Object obj){
        if(obj == null || !(obj instanceof User))
            return false;
        if(this == obj)
            return true;
        User u = (User)obj;
        //if(用户名相同 && 家庭住址相同)  此时两个对象相等
        /*
        if(this.name.equals(u.name) && this.addr.equals(u.addr))
            return true;
        return false;
        */
        return this.name.equals(u.name)
            && this.addr.equals(u.addr);  //这里分别调用的是String类和Address类的equals()
    }
}

class Address{
    String city;
    String street;
    String zipcode;
    
    public Address(){}
    public Address(String city,String street,String zipcode){
        this.city = city;
        this.street = street;
        this.zipcode = zipcode;
    }
    
    //这里的equals()判断的是Address对象和Address对象是否相等
    @Override
    public boolean equals(Object obj){
        if(obj == null || !(obj instanceof Address))
            return false;
        if(this == obj)
            return true;
        Address a = (Address)obj;
        //if(城市相同 && 街道相同 && 邮编相同)  此时两个对象相等
        /*
        if(this.city.equals(a.city)
            && this.street.equals(a.street)
            && this.zipcode.equals(a.zipcode))
            return true;
        return false;
        */
        return this.city.equals(a.city)
            && this.street.equals(a.street)
            && this.zipcode.equals(a.zipcode);  //这里调用的都是String类的equals()
    }
}
View Code
复制代码

 


 

p4、关于Object类中的 finalize()方法
1、在Object类中的源代码:
    protected void finalize() throws Throwable{}
  GC:负责调用finalize()方法
2、finalize()方法没有方法体,而且是protected修饰的
3、finalize()方法只需要重写,不需要程序员手动调用,JVM的垃圾回收器GC程序会自动调用这个方法
4、finalize()方法的执行时机:
  当一个Java对象即将被垃圾回收器回收的时候,垃圾回收器负责调用finalize()方法
5、finalize()方法实际上是SUN公司为java程序员准备的一个时机:垃圾回收时机
  如果希望在对象销毁时机执行一段代码的话,这段代码要写到finalize()方法当中
6、提示:Java中的垃圾回收器不轻易启动的,垃圾太少或时间没到则可能不会启动

7、建议启动垃圾回收器:
    System.gc();

示例1:垃圾回收器自动调用finalize()方法

复制代码
public class Test{
    public static void main(String[] args){
        /*
        //创建对象
        Person p  = new Person();
        //怎么把Person对象变成垃圾?
        p = null;
        */
        
        /*
        //多造点垃圾
        for(int i = 0;i < 1000000;i++){
            Person p = new Person();
            p = null;
        }
        */
        
        for(int i = 0;i < 1000;i++){
            Person p = new Person();
            p = null;
            //有一段代码可以建议启动垃圾回收器
            if(i % 10 == 0){  //每10个对象启动一次
                System.gc();  //建议启动垃圾回收器
            }
        }
    }
}

//项目开发中有这样的业务需求:所有对象在JVM中被释放的时候,请记录一下释放时间!
//记录对象被释放的时间点,这个负责记录的代码就写到finalize()方法中
class Person{
    //重写finalize方法
    //Person类型的对象被垃圾回收器回收的时候,垃圾回收器负责调用:p.finalize();
    protected void finalize() throws Throwable{
        System.out.println(this + "即将被销毁!");
    }
}
View Code
复制代码

 


 

 

p5、关于Object类中的 hashCode()方法
1、源代码:
    public native int hashCode();
  这个方法不是抽象方法,带有native关键字,底层调用C++程序
2、hashCode()方法的返回值是一个整型的哈希码:
  实际上是一个java对象的内存地址,经过哈希算法,得出的一个值,所以hashCode()方法的执行结果可以等同看做一个Java对象的内存地址

示例1:Object类中的 hashCode()方法

复制代码
public class Test{
    public static void main(String[] args){
        Object o = new Object();
        int hashCodeValue = o.hashCode();

        //对象的内存地址经过哈希算法转换成一个数字,可以等同看作内存地址
        System.out.println(hashCodeValue);  //366712642
        
        MyClass mc = new MyClass();
        int hashCodeValue2 = mc.hashCode();
        System.out.println(hashCodeValue2);  //1829164700
        
        MyClass mc2 = new MyClass();
        System.out.println(mc2.hashCode());  //2018699554
    }
}

class MyClass{
    
}
View Code
复制代码

 


 

p6、匿名内部类
1、什么是内部类?
  在类的内部又定义了一个新的类,称为内部类
2、内部类的分类:
    静态内部类:类似于静态变量
    实例内部类:类似于实例变量
    局部内部类:类似于局部变量
3、使用内部类编写的代码,可读性很差,能不用尽量不用
4、匿名内部类:
  是局部内部类的一种,因为这个类没有名字而得名

5、学习匿名内部类只为能认识这类代码,但不建议使用匿名内部类
  缺点1:太复杂、太乱、可读性差
  缺点2:因为类没有名字,所以不能重复使用

示例1:内部类概述

复制代码
public class Test{
    //静态变量
    static String country;
        
    //该类在类的内部,故为内部类
    //有static修饰,故为静态内部类
    static class Inner1{}

    //实例变量
    int age;
        
    //该类在类的内部,故为内部类
    //无static,故为实例内部类
    class Inner2{}

    public void doSome(){
        //局部变量
        int i = 100;
            
        //该类在类的内部,故为内部类
        //局部内部类
        class Inner3{}
    }
        
    public void doOther(){
        //doSome()方法中的局部内部类Inner3,在doOther()方法中不能使用
    }
    
    //main()方法 入口
    public static void main(String[] args){}
}
View Code
复制代码

示例2:接口 实现类 多态

复制代码
public class Test{
    //main()方法 入口
    public static void main(String[] args){
        //调用MyMath中的mySum方法
        MyMath mm = new MyMath();
        mm.mySum(new ComputeImpl(),100,200);
    }
}

//计算接口
interface Compute{
    //抽象方法
    int sum(int a,int b);
}

//Compute接口的实现类
class ComputeImpl implements Compute{
    //对方法的实现
    public int sum(int a,int b){
        return a+b;
    }
}

//数学求和
class MyMath{
    public void mySum(Compute c,int x,int y){
        int retValue = c.sum(x,y);
        System.out.println(x + "+" + y + "=" + retValue);
    }
}
View Code
复制代码

 

示例3:使用匿名内部类创建对象

复制代码
public class Test{
    //main()方法 入口
    public static void main(String[] args){
        //调用MyMath中的mySum方法
        MyMath mm = new MyMath();
        
        //这样写代码表示ComputeImpl这个类是有的
        //mm.mySum(new ComputeImpl(),100,200);
        
        //如果不编写实现类,那么使用匿名内部类创建的对象,表示ComputeImpl这个类名时没有的
        //这里表面上看好像直接new了接口,实际上后面的{}花括号代表了接口的实现
        //这里的{}话括号就是匿名内部类
        //不建议使用匿名内部类,因为一个类没有名字,就不能重复使用,而且代码太乱可读性太差
        //mm.mySum(new Compute(){接口的实现},100,200);
        mm.mySum(new Compute(){
            public int sum(int a,int b){
                return a + b;
            }
        },100,200);  //100+200=300
    }
}

//计算接口
interface Compute{
    //抽象方法
    int sum(int a,int b);
}

//Compute接口的实现类
/*
class ComputeImpl implements Compute{
    //对方法的实现
    public int sum(int a,int b){
        return a+b;
    }
}
*/

//数学求和
class MyMath{
    public void mySum(Compute c,int x,int y){
        int retValue = c.sum(x,y);
        System.out.println(x + "+" + y + "=" + retValue);
    }
}
View Code
复制代码

 

 

 

 

 

 

 

//即使再小的帆也能远航!

posted @   冬雪雪冬小大寒  阅读(56)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示