Java基础之(十八)equals方法

说明
Java程序中测试两个变量是否相等有两种方式:一种是利用==运算符;一种是利用equals函数。

==运算符

当使用==来判断两个变量是否相等时,如果两个变量是基本类型变量,且都是数值类型,则只要两个变量的值相等,就将返回true.

但对于两个引用变量,它们必须指向同一个对象时,==判断才会返回true。==不可用于比较类型上没有父子关系的两个对象。下面程序示范了使用==来判断两种类型变量是否相等的结果。

        int i = 65;
        float f = 65.0f;
        //将输出true
        System.out.println("65和65.0f是否相等?"+ (i==f));
        char c = 'A';
        //将输出true
        System.out.println("65和A是否相等?"+ (i==c));
        String str1 = new String("hello!");
        String str2 = new String("hello!");
;       //将输出false
        System.out.println("str1和str2是否相等?"+ (str1==str2));
        //String类与Math类没有父子关系,将编译出错
        //System.out.println("hello"== new Math());
输出结果:
6565.0f是否相等?true
65A是否相等?true
str1和str2是否相等?false

从结果可以看到,65和65.0f和’A’相等。但对于str1 和 str2,它们都是引用型变量,分别指向两个不同的String对象,因此str1和str2两个变量不相等。

那如果我们改成如下这样:

String str1 = "hello!";
String str2 = "hello!";
System.out.println("str1和str2是否相等?"+ (str1==str2));
输出结果:
str1和str2是否相等?true

这里的输出显示,两个字符串文字保存为一个对象。就是说,上面的代码只创建了一个String对象。

那么”hello”和new String(“hello”)具体区别在哪呢?

提到这里,就正好来解答一个面试问题:

String s = new String(“xyz”)创建了几个对象?

当Java程序直接使用形如”hello”的字符串直接量时,JVM将会使用常量池来管理这些字符串。

String str1 = “hello”;这行代码被执行的时候,JAVA虚拟机首先在字符串池中查找是否已经存在了值为”hello”的这么一个对象,它的判断依据是String类equals(Object obj)方法的返回值。如果有,则不再创建新的对象,直接返回已存在对象的引用;如果没有,则先创建这个对象,然后把它加入到字符串池中,再将它的引用返回。由于str1 和 str2的文本字符串相同,因此只创建了一个字符串对象”hello”。

Java中所有的字符串文字[字符串常量]都是一个String的对象。

String str1 = new String(“hello”);这行代码被执行的时候,JVM会先在常量池中创建一个String对象“hello”,然后再通过String类的构造器来创建一个新的String对象,新创建的String对象将会保存在堆内存中。因此这行代码实际产生了两个对象。

那么 String str = “a”+”b”+”c”创建了几个对象?
答案是一个;
编译器会对”a”+”b”+”c”这样的代码在编译期间优化成一句,即字符串合并成一个字符串相当于(String str= “abc”);也就是说,在代码编译后的运行期间只会生成一个临时对象。

equals函数

JVM常量池保证相同的字符串常量只能有一个。如果对于两个指向不同对象的引用变量,只需要判断它们的”值”是否相等来决定两个变量是否相等,此时就可以利用String对象的equals方法来进行判断。
比如,上面代码中可改写比较str1 和 str2的方法:

        String str1 = new String("hello!");
        String str2 = new String("hello!");
        System.out.println(str1.equals(str2));
输出结果:
true

equals方法在什么地方

equals方法是Object类提供的一个实例方法,而Object类又是所有类的父类,因此所有的类里面都有equals函数,所有引用变量都可调用该方法来判断是否与其他变量相等。

String类的equals方法判断两个字符串相等的标准是:只要两个字符串所包含的字符串序列相同,通过equals方法将返回true,否则返回false。

总的来说,equals的作用就是比较两个对象的内容是否相等,就好比去比较两个人的长相是否相同,它比较的两个对象是独立的。
通常情况下,两个对象的内容相等需要符合两个条件:

  • 对象的类型相同(可以使用instanceof运算符进行比较)

  • 两个对象的成员变量的值完全相同

重写equals方法

先看下面使用equals比较两个对象的代码:

class Person{
    String name;
    int age;
}
public class Test {
    public static void main(String[] args){
        Person p1 = new Person();
        Person p2 = new Person();
        System.out.println(p1.equals(p2));
    }
输出结果:
false

使用equals判断两个对象的标准实际上和==运算符没有区别,同样要求两个引用变量指向同一个对象才会返回true(String已经重写了Object的equals方法,因此上面代码才会返回true),因此这个Object提供的equals方法没有太大的作用,如果希望采用自定义的相等标准,则可重写equals方法来实现。

根据上面列出的两点要求,下面程序示范了重写equals方法:

class Person{
    String name;
    int age;

    public boolean equals(Object obj){
        //如果两个变量指向同一对象,this指调用equals方法的那个变量
        if(this == obj){
            return true;
        }
        //判断obj类型是否和this类型相同,this是Person类型
        boolean b = obj instanceof Person;
        //如果相同
        if(b){
            //向下转型
            Person p = (Person)obj;
            //判断两个变量的成员变量是否相同
            if(this.age == p.age&&this.name.equals(p.name)){
                return true;
            }
            else{
                return false;
            }
        }

        else{
            return false;
        }

    }
public class Test {
    public static void main(String[] args){
        Person p1 = new Person();
        p1.name = "zhangsan";
        p1.age = 10;

        Person p2 = new Person();
        p2.name = "lisi";
        p2.age = 10;

        Person p3 = new Person();
        p3.name = "zhangsan";
        p3.age = 10;
        System.out.println(p1.equals(p2));
        System.out.println(p1.equals(p3));
    }

}
输出结果:
false
true

代码中之所以用this.name.equals(p.name)而不用==运算符来比较两者是否相等,是因为name是String类型引用变量,String已经重写了equals方法,可以拿来直接比较两者的内容是否相同。

==和equals方法区别

==操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同。
如果一个变量指向的数据是对象类型的,那么这时候涉及了两块内存,对象本身占用一块内存(堆内存),变量占用一块内存(栈内存),例如Object obj = new Object();变量obj所对应的内存中存储的数值就是对象占用的那块内存的首地址,==操作符就是用来比较两个变量是否指向堆内存中的同一块地址,即比较这两个变量所对应的内存(栈内存)中的数值是否相等。

equals方法主要用于比较两个独立对象的内容是否相同,首先是否类型相同,其次是否成员变量相同。

你可能感兴趣的:(Java基础)