专栏首页无题谈谈Java中equals和==的区别和使用场景

谈谈Java中equals和==的区别和使用场景

讨论一下Java中equals和==的区别,这个问题看似浅显,还是有不少情况需要注意。阅览了网上一些文章,都比较片面。在此做一下详细的整理。

先直接上结论::

1.当比较对象为基本数据类型的时候,”==“比较的是二者在栈内存中的值。object默认的equals方法,是比较两个对象的引用是不是相同

2.当比较对象为复杂数据类型的时候,当且仅当该equals方法参数不是 null,两个变量的类型、内容都相同,比较结果为true。但string类有常量池的缘故较为特殊。

3.当比较对象为实体类的时候,不重写equals方法,采用object默认的equals方法,是比较两个对象的引用是不是相同。比较的是二者在堆内存中的引用地址,无意义,一般在实体类中进行重写equals方法,自定义比较规则。

java中的数据类型,可分为两类:

1.基本数据类型,也称原始数据类型的比较。

byte,short,char,int,long,float,double,boolean 他们之间的比较,应用双等号(==),比较的是他们的值。

示例:

public class Test {

public static void main(String[] args) {  

  int i=5;  
  int j=5;  

  if(i==j) System.out.println("i和j相等!");  
  else System.out.println("不相等!");  
  }

运行结果: “i和j相等!”

因为此时比较对象为基本数据类型,所以“==”比较的是它们存放于虚拟机栈内存中的值。

2.复杂数据类型的比较

在Java API中,有些类重写了equals()方法,它们的比较规则是:当且仅当该equals方法参数不是 null,两个变量的类型、内容都相同,则比较结果为true。这些类包括:String、Double、Float、Long、Integer、Short、Byte、、Boolean、BigDecimal、BigInteger等等,太多太多了,但是常见的就这些了,具体可以查看API中类的equals()方法,就知道了。

深入到内存中。==就是比较堆内存的值是否相等(对象地址存放在堆内存),equals()就是比较栈内存的值(对象的值存在于栈内存)。String有个常量池。String a=”abc”;String b=”abc”;a==b是返回true的,就是因为常量池的原因,实际上a和b是同一个对象。但是String a=”abc”;String a=new String(“abc”);这样a==b就是返回flase了,a和b就不是同一个对象(他们的地址不等。)

原来,程序在运行的时候会创建一个字符串缓冲池当使用 s2 = “Monday” 这样的表达是创建字符串的时候,程序首先会在这个String缓冲池中寻找相同值的对象,在第一个程序中,s1先被放到了池中,所以在s2被创建的时候,程序找到了具有相同值的 s1 将s2引用s1所引用的对象”Monday” 第二段程序中,使用了 new 操作符,他明白的告诉程序:”我要一个新的!不要旧的!”于是一个新的”Monday”Sting对象被创建在内存中。他们的值相同,但是位置不同,一个在池中游泳一个在岸边休息。哎呀,真是资源浪费,明明是一样的非要分开做什么呢?

3.实体类的比较

当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。

JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地 址。

对于复合数据类型之间进行equals比较,在没有覆写equals方法的情况下,他们之间的比较还是基于他们在内存中的存放位置的地址值的,因为Object的equals方法也是用双等号(==)进行比较的,所以比较后的结果跟双等号(==)的结果相同。

示例:

public class Student {  

    String name;  

        public Student(){  

    }  

    public Student(String name){  

    this.name=name;  

}                                                            

public class Test {  

    public static void main(String[] args) {  

      Student s = new Student("BlueSky");  
      Student s1=new Student("BlueSky");  

      if(s==s1)  System.out.println("s和是s1相等!");  
      else System.out.println("s和是s1不相等!");  

      if(s.equals(s1)) System.out.println("s和是s1相等!");  
      else System.out.println("s和是s1不相等!");  
}  

}

运行结果: s和是s1不相等! s和是s1不相等!

结果验证了Object类的equals()方法用来比较是否一个对象是利用内存地址比较,所以在定义一个类的时候,如果涉及到对象的比较(通过我们要比较内容),应该重写equals()方法。重写的一般规则是:

1、先用“==”判断是否相等。

2、判断equals()方法的参数是否为null,如果为null,则返回false;因为当前对象不可能为null,如果为null,则不能调用其equals()方法,否则抛java.lang.NullPointerException异常。

3、当参数不为null,则如果两个对象的运行时类(通过getClass()获取)不相等,返回false,否则继续判断。

4、判断类的成员是否对应相等。往下就随意发挥了。呵呵!

我们对实体进行比较的时候往往要比较的是里面的值,所以我们为了达到这个目的,要在实体类里面重写equals()方法,进行对象里面的内容比较。如上面,我们在Student类中重写equals()方法。

重写equals()方法后再次进行比较: Student类:

public class Student {  

String name;  

public Student(){  

}  

public Student(String name){  

    this.name=name;  

}  


public boolean equals(Object obj) {  
    if (this == obj)      //传入的对象就是它自己,如s.equals(s);肯定是相等的;  
        return true;   
    if (obj == null)     //如果传入的对象是空,肯定不相等  
        return false;  
    if (getClass() != obj.getClass())  //如果不是同一个类型的,如Studnet类和Animal类,  
                                       //也不用比较了,肯定是不相等的  
        return false;  
    Student other = (Student) obj;       
    if (name == null) {  
        if (other.name != null)  
            return false;  
    } else if (!name.equals(other.name))   //如果name属性相等,则相等  
        return false;  
    return true;  
}  

}

测试类Test:

public class Test {  

public static void main(String[] args) {  

  Student s = new Student("BlueSky");  
  Student s1=new Student("BlueSky");  

  if(s.equals(s1)) System.out.println("s和是s1相等!");  
  else System.out.println("s和是s1不相等!");  
}  

}

运行结果: “s和是s1相等!”

结论:

1.当比较对象为基本数据类型的时候,”==“比较的是二者在栈内存中的值。

2.当比较对象为复杂数据类型的时候,当且仅当该equals方法参数不是 null,两个变量的类型、内容都相同,则比较结果为true。但string类有常量池的缘故较为特殊。

3.当比较对象为实体类的时候,不重写equals方法,比较的是二者在堆内存中的引用地址,无意义,一般在实体类中进行重写equals方法,自定义比较规则.

附:Object的getClass方法与getName方法

getClass方法:

类型:public final Class<? extends Object> getClass() 功能:返回该对象的运行时类的Java.lang.Class对象(API上的解释) 有方法类型可以知道,该方法只能由类的实例变量调用 例子:

[java] view plain copy
JButton b1 = new JButton("button1");  
System.out.println(b1.getClass());  

输出: class javax.swing.JButton

class属性 当你要获得一个类的Class对象时(作函数参数的时候),你不能调用getClass方法,那你只能用类名.class来达到效果 例子:

[java] view plain copy
System.out.println(JButton.class);  

输出: class javax.swing.JButton

getName方法:

类型:public String getName() 功能:以String形式返回次Class对象所表示的实体名称 例子:

[java] view plain copy
JButton b1 = new JButton("button1");  
System.out.println(b1.getName());  

输出: javax.swing.JButton

可以发现用class属性和getClass返回的输出是一样的,用getName返回的比前面两种少了class和一个空格。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Rabbitmq基本原理

    Exchange类似于数据通信网络中的交换机,提供消息路由策略。rabbitmq中,producer不是通过信道直接将消息发送给queue,而是先发送给Exch...

    于霆霖
  • BlockingQueue源码分析

    * ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。 LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。 ...

    于霆霖
  • 各RDB与Nosql性能与特点总结

    最近考虑到数据库包括各种缓存到底面对高并发情况性能到底是怎么样的,所以多方收集整理成此篇,以后也会持续更新。 mysql: 1.性能从10万条规模升到100万...

    于霆霖
  • Android基础-系统架构分析,环境搭建,下载Android Studio,AndroidDevTools,Git使用教程,Github入门,界面设计介绍

    应用层(Applications),应用框架层(Application Framework),系统运行层(Libraries和android runtime)和...

    达达前端
  • 修改Linux下已挂载的分区目录路径

    1、创建新的路径目录:先进入根目录:#cd / 然后创建需要创建的目录的路径:mkdir /home/wwwroot

    似水的流年
  • 修改Linux下已挂载的分区目录路径

    查看当前的目录名以及挂载点:#df –h 1、创建新的路径目录:先进入根目录:#cd / 然后创建需要创建的目录的路径:mkdir /home/www...

    似水的流年
  • AsciiDoc 简介

    Markdown 是现在最流行的轻量级标记语言,Github、Stack Overflow、Smashing Magazine 等网站都使用 Markdown。...

    Tsong khapa
  • Windows Phone 7 WebBrowser 中文乱码问题

    通过WebBrowser直接请求网页,是正常显示的,只是通过获取到字符串,再通过NavigateToString()就会显示乱码. 中文转换成 Unicode编...

    张善友
  • netdata安装

    Linux性能实时监测工具,以web的可视化方式展示系统及应用程序的实时运行状态(包括cpu、内存、硬盘输入/输出、网络等linux性能的数据)。炫酷的界面来显...

    薛定喵君
  • centos7 安装netdata及使用

    netdata官网:https://www.netdata.cloud/about netdata文档:https://docs.netdata.cloud/

    shaonbean

扫码关注云+社区

领取腾讯云代金券