Java进阶(4)——Object类中toString(),equals(),finalize(),hashCode()方法及匿名内部类介绍

本部分为动力节点java入门视频的学习笔记,主要内容包括API介绍,如何查找源码以及源码的解释文档。toString()方法、equals()方法及其优化、String类、finalize()方法、hashCode()方法以及匿名内部类的使用。

相关介绍

API
  • 应用程序编程接口(Application Program Interface)
  • 整个JDK的类库就是一个javase的API
  • 每一个API都会配置一套API帮助文档
  • SUN公司提前写好的这套类库就是API
查看方法相关资料

第一种方法:查看源代码
第二种方法:查看Java类库的帮助文档

Objects方法

  • 1.protected Object clone()//对象克隆
  • 2.int hashCode()//获取哈希值
  • 3.boolean equals(Object obj)//判断对象是否相等
  • 4.String toString()//对象转字符串
  • 5.protected void finalize()//垃圾回收器负责调用的方法
toString()

通过调用这个方法可以将一个"java对象"转换成字符串形式。

源码
getClass().getName() + '@' +Integer.toHexString(hashCode())

Sun公司开发java语言的时候,建议所有的子类都去重写toString()方法
重写的方向:简洁,详实,易阅读

实例
public class Test {
    public static void main(String[] args){
        MyTime t1 = new MyTime(1970,1,1);
        String s1 = t1.toString();
        System.out.println(s1);//重写之前输出结果是:MyTime@73035e27
        //重写之后输出结果是:1970年1月1日
    }
}
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()方法
    //简洁详实

    public String toString(){
        return this.year +"年" + this.month + "月" + this.day + "日";
    }
}
equals()

源码

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

在Object类中的equals方法当中,默认采用的是“==”判断两个Java对象是否相等

设计目的是判断两个对象是否相等
研究一下Object类给的这个默认的equals方法够不够用?

实例
public class test{
    public static void main(String[] args) {
        MyTime mytime = new MyTime(2022,7,19);
        MyTime mytime1 = new MyTime(2022,7,19);
        MyTime mytime2 = new MyTime(2022,7,20);
        System.out.println(mytime.equals(mytime1));
        System.out.println(mytime1.equals(mytime2));
    }
}
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;
    }


    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;
    }
}
instanceof关键字

定义

用来测试一个对象是否为一个类的实例

解释

当程序执行向下转型的操作时如果父类对象不是子类对象的实例,就会发生ClassCastException异常,所以在执行向下转型的时候需要判断父类对象是否为子类对象的实例。这个判断用instanceof操作符来完成。使用instanceof操作符的表达式返回值为布尔型。如果返回值为true,说明某个类的对象是某个类的实例对象;如果返回值为false,说明不是。

某个类的对象 instanceof 某个类
初步优化
public boolean equals(Object obj){
    //当年相同月相同和日相同,则两个对象相等

    int year1 = this.year;
    int month1 = this.month;
    int day1 = this.day;

    if(obj == null){
        return false;
    }
    if(!(obj instanceof MyTime)){
        return false;
    }
    if(this == obj){
        return true;
    }
    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;
}
深度优化
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;
}

可以发现这段代码和alt + insert生成的equals代码是基本一致的

  @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MyTime myTime = (MyTime) o;
        return year == myTime.year && month == myTime.month && day == myTime.day;
    }

对于生成的方法如果不能满足需要,可以自己重写。

String
  • 1.String类型的数据已经重写了equals和toString()方法。
  • 2.java中所有的引用数据类型统一使用equals方法来判断是否相等,如String
  • 3.java中所有的基本数据类型采用==判断是否相等,如int…
实例
public class test{
    public static void main(String[] args) {
        User u1 = new User("小凡",new Address("河南","信阳","111"));
        User u2 = new User("小凡",new Address("河南","信阳","111"));
        System.out.println(u1.equals(u2));
    }
}

class User{

    String name;
    Address addr;
    public User(){

    }
    public User(String name,Address addr){
        this.name = name;
        this.addr = addr;
    }

    //重写equals方法
    public boolean equals(Object obj){
        if(obj == null || !(obj instanceof User)) return false;
        if(this == obj) return true;
        User u = (User)obj;
        return this.name.equals(u.name) && this.addr.equals(u.addr);
    }

}

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;
    }
    
}

输出

false

解释

为什么?return this.name.equals(u.name) && this.addr.equals(u.addr);这里的address中的equals没有重写,导致在比较this.addr.equals(u.addr)的时候,比较的是User对象中的address。而初始化的时候,
User u1 = new User(“小凡”,new Address(“河南”,“信阳”,“111”));
User u2 = new User(“小凡”,new Address(“河南”,“信阳”,“111”));
初始化了两个对象,所以this.addr代表的内存地址,u.addr也代表的是内存地址。
且调用的“老祖宗”的equals方法。所以返回false。

所以需要注意,equals要写的彻底。在Address类中也要重写equals。

public class test{
    public static void main(String[] args) {
    
        //多态,自动类型转换,父类指向子类
        Object o1 = new String("Hello world!");
        Object o2 = new User();
        Object o3 = new Address();
        
        
        
        User u1 = new User("小凡",new Address("河南","信阳","111"));
        User u2 = new User("小凡",new Address("河南","信阳","111"));
        System.out.println(u1.equals(u2));
    }
}

class User{

    String name;
    Address addr;
    public User(){

    }
    public User(String name,Address addr){
        this.name = name;
        this.addr = addr;
    }

    //重写equals方法
    public boolean equals(Object obj){
        if(obj == null || !(obj instanceof User)) return false;
        if(this == obj) return true;
        User u = (User)obj;
        return (this.name.equals(u.name)) && (this.addr.equals(u.addr));
    }

}

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;
    }

    public boolean equals(Object obj){
        if(obj == null || !(obj instanceof Address)) return false;
        if(this == obj) return true;
        Address ad = (Address)obj;
        return (this.city.equals(ad.city)) && (this.street.equals(ad.street)) && (this.zipcode.equals(ad.zipcode));
    }

}

输出

ture
总结

该段代码中有3个equals,第一个equals代表的是User中重写的equals。第二个equals代表的是String中写好的equals。第三个equals代表的Address中重写的equals。开发中比较两个对象用的就是equals方法,如果没有重写会出现问题。

finalize()(非重点,了解即可)
  • 1、这个方法是protected修饰的,在Object类中这个方法的源代码是?
    GC:负责调用finalize()方法
protected void finalize() throws Throwable{ }
  • 2、这个方法不需要程序员手动调用,JVM的垃圾回收器负责调用这个方法。
    finalize()只需要重写,重写完将来自动会有程序来调用。
  • 3、finalize()方法的执行时机:当一个java对象即将被垃圾回收器回收的时候,垃圾回收器负责调用finalize()方法
  • 4、finalize()方法实际上是SUN公司为java程序员准备的一个时机,垃圾销毁时机。如果希望在对象销毁时机执行一段代码的话,这段代码写道finalize()方法当中。
  • 5、静态代码块的作用是什么?
 static{
     
 }
  • 6、静态代码在类加载时刻执行,并且只执行一次。这是一个SUN准备的类加载时机。
    finalize()方法同样也是SUN为程序员准备的一个时机,这个时机就是垃圾回收时机。

  • 7、提示:
    java中的垃圾回收器不是轻易启动的,垃圾太少,或者时机没到,种种条件下,有可能启动,也有可能不启动。

import jdk.swing.interop.SwingInterOpUtils;

public class test{
    public static void main(String[] args) {
        Person p = new Person();
        //怎么把Person对象变成垃圾?
        p = null;

        //java

        //多造点垃圾
        for(int i = 0;i<1000;i++){
            Person pi = new Person();
            pi = null;

            //有一段代码可以建议垃圾回收器启动(只是建议,可能不启动,也可能启动)
            System.gc();
        }


    }
}

class Person{
    //重写finalize()方法
    //Person类型的对象被垃圾回收器回收的时候,垃圾回收器负责调用:p.finalize();
    protected void finalize() throws Throwable{
        System.out.println(this + " destroyed");
    }
}

输出

Person@3eef63a9 destroyed
Person@65960c95 destroyed
Person@435557da destroyed
Person@488ac9e1 destroyed
Person@dbd0972 destroyed
Person@589a5ef4 destroyed
Person@319829ba destroyed
Person@2fc32ba9 destroyed
Person@4ad051ba destroyed
Person@40b7cbea destroyed

hashCode()
源码
public native int hashCode();

定义

hashCode方法返回哈希值:实际上是一个java对象的内存地址,经过哈希算法得出的一个值。所以hhashCode()方法的执行结果可以等同看作一个java对象的内存地址。

实例
public class interfaceTest{
    public static void main(String[] args) {
        Object o = new Object();
        int hashCodeValue = o.hashCode();

        System.out.println(hashCodeValue);

        MyClass mc = new MyClass();
        System.out.println(mc.hashCode());

        MyClass mc1 = new MyClass();
        System.out.println(mc1.hashCode());
    }
}

class MyClass{

}

输出

764977973
2129789493
668386784
匿名内部类

定义

在类的内部又定义了一个新的类。被称为内部类。因为这个类没有名字,所以称作匿名内部类。学习匿名内部类主要是为了能够读懂别人写的代码。会导致可读性差,所以尽量不用。

public class scanner{
    public static void main(String[] args) {
        MyMath mm = new MyMath();

        mm.mySum(new Compute() {
            public int sum(int a, int b) {
                return a + b;
            }
        },100,200);

        mm.mySum(new ComputeImpl(),100,300);
    }
}

class MyMath{
    public void mySum(Compute c, int x, int y) {
        int retValue = c.sum(x,y);
        System.out.println(x + "+" +y + "=" + retValue);
    }
}

interface Compute{
    int sum(int a,int b);
}

class ComputeImpl implements Compute{

    @Override
    public int sum(int a, int b) {
        return a+ b;
    }
}

输出

100+200=300
100+300=400

ok,暂时完结~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

疯狂java杰尼龟

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

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

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

打赏作者

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

抵扣说明:

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

余额充值