Java基础39 Object类(节选)



Object类

Object类:Java中lang包的类,是类层次结构的根类,每个类都使用Object作为超类。所有对象(包括数组)都实现这个类的方法。

Object类所含有的方法

  • clone()
  • equals(Object obj)
  • finalize()
  • getClass()
  • hashCode()
  • notify()
  • notifyAll()
  • toString()
  • wait()
  • wait(long timeout)
  • wait(long timeout, int nanos)

一、 equals( )

boolen | equals(Object ob) : 指示其他某个对象是否与此对象"相等"。

● == 与 equals的对比(☆)

(1)== 运算符

  1. == : 既可以判断基本类型,又可以判断引用类型
  2. == : 如果判断基本类型,判断的是值是否相等。
  3. == : 如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象。

例如:

public static void main(String[] args){
    	A a = new A();
    	A b = a;
    	A c = b;
    	System.out.println( a == c);
    	System.out.println( b == c);
}

class B{}
class A extends B{}

创建了一个A对象,现在有一个a引用,指向了A对象,再有一个b引用,指向了A对象,最后再创建一个c引用也指向A对象,现在用 == 号来比较a与c,而由上述概念得知:== 符号在比较引用类型时,比较的是它们所指向的地址值,而明显a与c指向的都是A对象,即地址值相同,所以a与c比较后返回的是true,同理b == c返回的也是true。

现在增加一个判断

B bObj = a;
Sysout.println(bObj == c);

这时创建一个向上转型的对象,而此时bObj指向的也是A对象,所以最后比较的地址值与c依然相等,最后输出的结果也是true。

(2)equals方法

equals

  1. Object类中的方法,只能判断引用类型
  2. 默认判断的是地址值是否相等,子类中往往重写该方法,用于判断内容是否相等。比如:Integer,String

String类的equals方法(JDK源码)

//把Object的equals方法重写了,变成了比较两个字符串值是否相同
if(anObject instanceof String){//判断类型
      String anotherString = (String)anObject; //向下转型
      int n = value.lenghth;
      if(n == anotherString.value.length){ //如果长度相同
           char v1[] = value;
           char v2[] = anotherString.value;
           int i = 0;
           while(n-- ! = 0){ //一个一个比较字符
               if(v1[i] != v2[i])
                   return false;
               i++;
           }
           return true; //如果两个字符串的所有字符都相等,则返回true
       }
}
return false //如果比较的不是字符串,则直接返回false

Object类的equals方法(JDK源码)

//Object 的 equals 方法默认就是比较对象地址是否相同
//也就是判断两个对象是不是同一个对象。
public boolean equals(Object obj){
	return (this == obj);
}

Integer类的equals方法(JDK源码)

public boolean equals(Object obj){
	if(obj instanceof Integer){
		return value == ((Integer)obj).intValue();
	}
	return false;
}

Integer integer1 = new Integer(1000);
Integer integer2 = new Integer(1000);
System.out.println(integer1 == integer2); //false
System.out.println(integer1.equals(integer2)); //true

● equals方法练习

实例1

判断两个Person对象的内容是否相等,如果两个Person对象的各个属性值都一样,则返回true,反之false。

创建Person类

class Person{
    private String name;
    private int age;
    private char gender;

    public Person(String name, int age, char gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }
}

创建test类

如果现在在主方法里直接调用equals方法,则调用的是Object类中的equals方法,因为Person没有继承任何类,默认继承的是Object类,而Object类中的equals方法相当于 “==” 来判断,比较的是地址值,很明显现在创建了两个对象,ps1和ps2,直接对比的话肯定返回的值是false,显然和我们想要的true不同。

public class test {
    public static void main(String[] args) {
    
        Person ps1 = new Person("jack",19,'男');
        Person ps2 = new Person("jack",19,'男');

        System.out.println(ps1.equals(ps2)); //false

    }
}

那如何得到正确的结果?那就是在Person中重写Object 的 equals方法。

在Person中重写Object的equals方法

    //重写Object的equals方法
    public boolean equals(Object obj){ //这里的Object obj指的是输出语句中传入的ps2
        //判断如果比较的两个对象是同一个对象,则直接返回true
        if(this == obj){ //这里的this指的是ps1
            return true;
        }
        //类型判断
        if(obj instanceof Person){ //是Person,才进行比较

            //向下转型,因为现在需要得到obj的各个属性
            Person p = (Person) obj;
            return this.name.equals(p.name) && this.age == p.age && this.gender == p.gender;
        }
        //如果不是Person,则直接返回false
        return false;
    }

实例2

看下列代码,分析输出的值为多少?

class Person{ //类 	
	public String name; 
 }

主方法

Person p1 = new Person();
p1.name = "ccc";

Person p2 = new Person();
p2.name = "CCC";

System.out.println(p1 == p2);
System.out.println(p1.name.equals(p2.name));
System.out.println(p1.equals(p2));

String s1 = new String("asdf");

String s2 = new String("asdf");
System.out.println(s1.equals(s2));
System.out.println(s1 == s2);

第一个输出语句

p1与p2的比较,由于是使用"==",所以比较的是地址值,而此时p1、p2分别是new出来的,并不是同一个对象,所以最后的结果为false

System.out.println(p1 == p2); //false

第二个输出语句

p1.name是字符串,已经把equals方法重写了,所以p1与p2比较的就是内容,显然内容一直,所以得到的结果应为true

System.out.println(p1.name.equals(p2.name)); //true

第三个输出语句

由于p1与p2都是自定义的类(Person),而此时的Person类中并没有重写equals方法,那么使用的就是他的父类Object的equals方法,所以比较的还是两者的地址值,显然最后的结果为false

System.out.println(p1.equals(p2)); //false

第四个输出语句

由于创建的是String类型的对象,必然使用的是String类重写的equals方法,所以两者比较的是内容的差异,显然二者都是一致的,最后的结果为true

System.out.println(s1.equals(s2)); //true

第五个输出语句

显然两者比较的是地址值,指向的不是同一个对象,所以最后的结果为false

System.out.println(s1 == s2); //false

运行结果

在这里插入图片描述

● 实例3

看下面的代码输出的是什么值?

int it = 65;
float fl = 65.0f;
System.out.println("65和65.0f是否相等? " + (it == fl));
char ch1 = 'A'; char ch2 = 12;
System.out.println("65和 'A' 是否相等? " + (it == ch1));
System.out.println("12和ch2是否相等? " + (12 == ch2));

String st1 = new String("hello");
String st2 = new String("hello");
System.out.println("str1和str2是否相等? " + (str1 == str2));

System.out.println("str1是否equals str2?" + (str1.equals(str2)));
System.out.println("hello" == new java.sql.Date());

false,false,true,true,true,true

第一个输出语句

由于是"==",所以判断的是值是否相等,而一个是int类型,一个是float类型,判断时自动转换,所以为true。

System.out.println("65和65.0f是否相等? " + (it == fl)); // true

第二个输出语句

同样是双等号,所以判断值是否相等,而 A 的ascll码值就为65,所以输出结果为true。

System.out.println("65和 'A' 是否相等? " + (it == ch1)); //true

第三个输出语句

同样是比较值,显然相等,所以输出结果为true。

System.out.println("12和ch2是否相等? " + (12 == ch2)); //true

第四个输出语句

两个对象str1、str2都是被new出来的新对象,所以地址值不同,结果为false

System.out.println("str1和str2是否相等? " + (str1 == str2)); //false

第五个输出语句

String类的equals方法必然重写,比较两者的值,相等,所以输出true。

System.out.println("str1是否equals str2?" + (str1.equals(str2))); //true

最后一个输出语句

编译器报错,因为编译器无法识别这两个对象的关系,它们既不是同一个类型,也没有继承关系,所以报错。

System.out.println("hello" == new java.sql.Date()); //报错

二、hashCode( )

hashCode( ) :返回该对象的哈希码值。

hashCode

  1. 提高具有哈希结构的容器的效率。
  2. 两个引用,如果指向的是同一个对象,则哈希值肯定相同,反之则不同(特殊情况除外)
  3. 哈希值主要根据地址号来的,不能完全将哈希值等价于地址!
  4. 后续在集合中介绍hashCode的重写。

hashCode的使用

现创建三个对象,一个aa1、aa2、aa3,其中aa1与aa2是新创建的对象,而aa3是指向aa1创建的对象。

public class test {
     public static void main(String[] args) {

        AA aa1 = new AA();
        AA aa2 = new AA();
        AA aa3 = aa1;

        System.out.println("aa1.hashCode() = " + aa1.hashCode());
        System.out.println("aa2.hashCode() = " + aa2.hashCode());
        System.out.println("aa3.hashCode() = " + aa3.hashCode());
    }
}

class AA{}

现在看通过hashCode输出的结果:

在这里插入图片描述
显然aa1与aa3是同一个对象,所以输出的值一致。

三、toString( )

toString( ) : 返回该对象的字符串表示。

  • 默认返回:全类名(包名 + 类名) + @ + 哈希值的十六进制(通过hashCode得到的整数),子类往往重写toString方法,用于返回对象的属性信息。

  • 重写toString方法,打印对象或拼接对象时,都会自动调用该对象的toString形式。

  • 当直接输出一个对象时,toString方法会被默认的调用。

Object的toString( ) 原码

ObjecttoString() 原码

(1) getClass().getName() 类的全类名(包名 + 类名)
(2) Integer.toHexString(hashCode()) 将对象的hashCode值转成16进制字符串

public String toString(){
	return getClass().getName() + "@" + Integer.toHexString(hashCode())
}

hashcode使用案例

创建Monster[name,job,sal]

直接使用toString

public class test {
     public static void main(String[] args) {

        Monster monster = new Monster("章鱼哥","恰人",1000);
         System.out.println(monster.toString() + "hashCode值 = " + monster.hashCode());
     }
}

class Monster{
    private String name;
    private String job;
    private double sal;

    public Monster(String name, String job, double sal) {
        this.name = name;
        this.job = job;
        this.sal = sal;
    }
}

运行效果

在这里插入图片描述

重写toString方法

class Monster{
    private String name;
    private String job;
    private double sal;

    public Monster(String name, String job, double sal) {
        this.name = name;
        this.job = job;
        this.sal = sal;
    }

    //重写toString方法,输出对象的属性
    //使用快捷键 alt + insert - >
    @Override
    //重写后,一般是把对象的属性值输出,当然程序员也可以自定义内容
    public String toString() {
        return "Monster{" +
                "name='" + name + '\'' +
                ", job='" + job + '\'' +
                ", sal=" + sal +
                '}';
    }
}

重写后继续调用monster,运行的结果如下所示:

在这里插入图片描述

当直接输出一个对象时,toString方法会被默认的调用。

还是以上面的代码为例,直接在输出语句中传入monster,实际上等价于monster.toString:

System.out.println(monster);//等价 monster.toString()

得到的结果如下所示:

在这里插入图片描述
但是可以注意到一个问题,那就是输出语句并没有重写hashcode,所以并没有输出哈希值。


四、finalize( )

finalize() :当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。

finalize()

  1. 当对象被回收时,系统自动调用该对象的finalize方法。子类可以重写该方法,做一些释放资源的操作。
  2. 什么时候被回收:当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用finalize方法。
  3. 垃圾回收机制的调用,是由系统来决定(即有自己的GC算法),也可以通过System.gc()主动触发垃圾回收机制

finalize使用实例

public class test {
     public static void main(String[] args) {

         Car bmw = new Car("宝马");
         //把bmw置空,此时Car现在就没人使用,就变为了垃圾对象
         //这时垃圾回收器就会回收(销毁)这个对象(堆释放)
         //在销毁对象前,会调用该对象的finalize方法
         // 此时程序员就可以在finalize中,写自己的业务逻辑代码(比如释放资源:数据库链接,或者打开文件等等)
         //如果程序员不重写finalize,那么就会默认调用Object类的finalize方法,如果程序员重写了finalize,就可以实现自己的逻辑。
         bmw = null;
     }
}

class Car{
    private String name;

    public Car(String name){
        this.name = name;
    }
}      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值