Java中的比较问题是一个很基础又很容易混淆的问题。今天就几个容易出错的点作一个比较详细的归纳与整理,希望对大家的学习与面试有帮助。

一、==与equals()的区别

首先,我们需要知道==与equals()的区别,==号比较的一直是地址值,对于基本数据类型来说,==比较实际上就是变量数值是否相等,而对于引用数据类型,比较的则是地址值。这里特别需要注意的是String类型,很容易想当然的使用==,很容易出错。equals()方法是Object类里的方法,我们知道Java中一切类都会默认继承Object类,所以类对象都会有equals()方法。Object类中equals()方法如下图所示:

由源码可以看出,Object类里的equals()方法底层也是用的==,所以它比较的其实也是地址值。所以如果想用equals()方法去作其他比较,我们需要重写equals()方法。

二、基本数据类型及其包装类

我们都知道,byte、short、int、long、boolean、char、double、float这八个是基本数据类型,它们声明的变量存放在栈内存中。而它们对应的包装类型(Byte、Short、Integer、Long、Boolean、Character、Double)定义的变量则存在于堆内存中。对于基本数据类型,它们的比较相对而言较为简单,即判断是否相等用==,比较大小用<、>、<=、>=即可。而对于包装类型,却有些不同。

首先对于判断是否相等,看如下代码的执行结果:

package dailytest;import org.junit.Test;/*** Java中的比较总结* @author yrr*/
public class JavaCompareTest {/*** Integer类型判断是否相等*/@Testpublic void test01() {int n3 = 48;System.out.println("--------使用new对象时,当值在[-127,128]之间时---------");Integer n7 = new Integer(48);Integer n8 = new Integer(48);System.out.println(n7 == n8);   //falseSystem.out.println(n7 == n3);   //true
        System.out.println("--------直接赋值方式,当值在[-128,127]之间时---------");Integer n1 = 48;Integer n2 = 48;System.out.println(n3 == n1); //trueSystem.out.println(n1 == n2); //trueSystem.out.println(n1.equals(n2)); //trueSystem.out.println(n1.equals(n3)); //trueSystem.out.println(n1.intValue() == n2.intValue()); //true
        System.out.println("--------直接赋值方式,当值不在[-127,128]之间时---------");Integer n4 = 128;Integer n5 = 128;int n6 = 128;System.out.println(n4 == n5);   //falseSystem.out.println(n4 == n6);   //trueSystem.out.println(n4.equals(n5));  //trueSystem.out.println(n4.equals(n6));  //trueSystem.out.println(n4.intValue() == n5.intValue());  //true//使用Integer.intValue()方法时需要注意验证是否为null,防止出现NullPointException
        }/*** Long类型判断是否相等*/@Testpublic void test02() {//这里需要注意,使用long定义时,不需要加L或者l,而使用Long时必须加,否则会报错//建设都加上,以示区别long n3 = 48L;System.out.println("--------使用new对象时,当值在[-127,128]之间时---------");Long n7 = new Long(48);Long n8 = new Long(48);System.out.println(n7 == n8);   //falseSystem.out.println(n7 == n3);   //true
        System.out.println("--------直接赋值方式,当值在[-127,128]之间时---------");Long n1 = 48L;Long n2 = 48L;System.out.println(n3 == n1); //trueSystem.out.println(n1 == n2); //trueSystem.out.println(n1.equals(n2)); //trueSystem.out.println(n1.equals(n3)); //trueSystem.out.println(n1.intValue() == n2.intValue()); //true
        System.out.println("--------直接赋值方式,当值不在[-127,128]之间时---------");Long n4 = 128L;Long n5 = 128L;long n6 = 128;System.out.println(n4 == n5);   //falseSystem.out.println(n4 == n6);   //trueSystem.out.println(n4.equals(n5));  //trueSystem.out.println(n4.equals(n6));  //trueSystem.out.println(n4.intValue() == n5.intValue());  //true//使用Long.intValue()方法时需要注意验证是否为null,防止出现NullPointException
        }
}

  针对上面的执行结果,作如下说明:

  1. 首先,对于new方法来声明一个Integer或者Long对象,因为new对象都是在堆里开辟一块空间,所以即便两者的数值相同,但对于==来说,比较的是地址值,所以会返回false。
  2. 对于基本数据类型的包装类,都重写了equals()方法,会比较数值大小,所以用equals()方法是可以根据数值大小进行判断的。
  3. 对于Integer变量与int变量比较的问题,会发现也是基于数值大小得出来的比较值,这是因为在比较时,Integer类型做了自动拆箱,转成了int类型。
  4. 前三点的解释,对所有包装类型都是适用的
  5. 对于直接赋值方式,值为48的两个Integer变量,用==号判断是true,而当值为128后,却为false。这是因为在底层,对于Integer n1 = 48;这种直接赋值的方式,其实调用了Integer.value()方法。我们可以简单看一下Integer.value()方法的源码,如下图所示:

我们可以看到,这里有个if判断,当输入的i在[-128,127]的范围内时,直接从IntegerCache数组中返回了。所以,对于在这个范围内的数值,返回的都是这个数组对应的地址值,因此用==号判断会返回true。而不在这个范围内的,是new出的对象,因此会返回false。这个结论对于Byte、Short、Integer、Long类型都成立(感兴趣的可以去看下它们对应的value()方法的源码),因为Byte类型的范围就是[-128,127],所以对于Byte类型来说,使用==与equals()没有区别。

而对于大小比较,使用>、<、<=、>=是没有问题的,它们会进行自动拆箱。但是我们通常建议使用以下两种方式来进行大小比较:

  • 调用xxxValue()方法转成基本数据类型进行比较
  • 使用compareTo()方法进行比较,在包装类中,都重写了compareTo()方法。查看compareTo()源码,可以看出,其实它底层使用的也是通过自动拆箱转成了对应的基本数据类型再进行比较的。

二、Java对象的比较

有了上面的介绍之后,对象的比较就比较容易了。原理都是一样的。

1. String类型的比较

需要注意的是,String类型不能直接使用>、<=、>=、<,会报编译异常。

package dailytest;import org.junit.Test;/*** Java中的比较总结* @author yrr*/
public class JavaCompareTest {@Testpublic void test03() {String s1 = new String("123");String s2 = new String("123");System.out.println(s1 == s2);    //false
       System.out.println(s1.equals(s2));String s3 = "234";String s4 = "234";System.out.println(s3 == s4);    //trueSystem.out.println(s3.equals(s4));    //true//System.out.println(s1 <= s3); //The operator < is undefined for the argument type(s) java.lang.String, java.lang.StringSystem.out.println(s1.compareTo(s3) < 0);   //true
    }
}

2. 类对象的比较

类对象比较结论也是一样的,但是相对于基本数据类型和String类型,较为复杂一点。

根据某一规则,判断两个对象是否相等,需要在被判断类中重写equals()方法,示例代码如下:

package dailytest;import org.junit.Test;/*** Java中的比较总结* @author yrr*/
public class JavaCompareTest {@Testpublic void test04() {Person p1 = new Person("yrr",18);Person p2 = new Person("yrr",18);System.out.println(p1 == p2);   //falseSystem.out.println(p2.equals(p1));  //true
    }
}class Person{private String name;    private Integer age;public Person() {}public Person(String name, Integer age) {this.name = name;this.age = age;}public String getName() {return name;}public Integer getAge() {return age;}@Overridepublic boolean equals(Object obj) {Person person = (Person) obj;return name.equals(person.getName()) && age.equals(person.getAge());}}

而如果要比较两个对象的大小(这也是常会问到的面试题),有两种方式:

  • 被比较类实现Comparable接口,并重写compareTo()方法
  • 自己定义实现了一个Comparator接口的类或者利用内部类,重写compare()方法
  • 两者的区别:前者定义在被比较类上,而后者定义在被比较类外。通过这种区别,两者的优缺点也很明显,前者简单,但需要对被比较类进行修改,而后者则不需要修改原代码,更加灵活。

第一种方式,示例代码如下:

package dailytest;import org.junit.Test;/*** Java中的比较总结* @author yrr*/
public class JavaCompareTest {@Testpublic void test5() {Person p1 = new Person("yrr",18);Person p2 = new Person("wx",19);System.out.println(p1.compareTo(p2) < 0);}
}class Person implements Comparable<Person>{private String name;    private Integer age;public Person() {}public Person(String name, Integer age) {this.name = name;this.age = age;}public Integer getAge() {return age;}@Overridepublic int compareTo(Person o) {return this.getAge() - o.getAge();}}

第二种方式,示例代码如下:

package comparator;import java.util.Arrays;
import java.util.Comparator;public class MyComparator {public static void main(String[] args) {User[] users = new User[] { new User("u1001", 25),  new User("u1002", 20), new User("u1003", 21) };Arrays.sort(users, new Comparator<User>() {@Overridepublic int compare(User o1, User o2) {return o1.getAge() - o2.getAge();}});for (int i = 0; i < users.length; i++) {  User user = users[i];  System.out.println(user.getId() + " " + user.getAge());  }  }}class User {  private String id;  private int age;  public User(String id, int age) {  this.id = id;  this.age = age;  }  public int getAge() {  return age;  }  public void setAge(int age) {  this.age = age;  }  public String getId() {  return id;  }  public void setId(String id) {  this.id = id;  }
}

  

 

转载于:https://www.cnblogs.com/yrrAwx/p/7897824.html

Java中的比较总结相关推荐

  1. java中实现具有传递性吗_Java中volatile关键字详解,jvm内存模型,原子性、可见性、有序性...

    一.Java内存模型 想要理解volatile为什么能确保可见性,就要先理解Java中的内存模型是什么样的. Java内存模型规定了所有的变量都存储在主内存中.每条线程中还有自己的工作内存,线程的工作 ...

  2. java中调用python

    在Java中调用Python </h1><div class="clear"></div><div class="postBod ...

  3. java中hashcode_浅谈Java中的Hash值

    1.Hash值有什么用? HashMap.HashTable.HashSet,所以涉及到使用Hash值进行优化存储的地方,都会用到HashCode.HashCode是Key,这种计算为提高计算的性能. ...

  4. JAVA中获取当前系统时间

    JAVA中获取当前系统时间 转自:http://www.cnblogs.com/Matrix54/archive/2012/05/01/2478158.html 一. 获取当前系统时间和日期并格式化输 ...

  5. Java中的对象和包

    什么是对象 对象就是实际生活中的事物,可以说一切事物都是对象. 对象的三个特点 1  对象的行为:这个对象能做什么, 例如包子是用来吃的 2  对象的状态:对象保持的一种状态,例如这个包子是热的还是凉 ...

  6. java中标识符,关键字,数据类型

    什么是标识符? 在java语言中用来给一个类,变量或方法命名的符号 标识符的命名规则 标识符可以由字母.数字.下划线(_).美元符($)组成,但不能包含 @.%.空格等其它特殊字符,不能以数字开头. ...

  7. Java中byte与16进制字符串的互相转换

    https://www.cnblogs.com/qinwangchen/p/5418028.html * Convert byte[] to hex string.这里我们可以将byte转换成int, ...

  8. JAVA中priorityqueue详解

    Java中PriorityQueue通过二叉小顶堆实现,可以用一棵完全二叉树表示.本文从Queue接口函数出发,结合生动的图解,深入浅出地分析PriorityQueue每个操作的具体过程和时间复杂度, ...

  9. 使用java中replaceAll方法替换字符串中的反斜杠

    今天在项目中使用java中replaceAll方法将字符串中的反斜杠("\")替换成空字符串(""),结果出现如下的异常: 1 java.util.regex. ...

  10. java 中常用的类

    java 中常用的类 Math Math 类,包含用于执行基本数学运算的方法 常用API 取整 l  static double abs(double  a) 获取double 的绝对值 l  sta ...

最新文章

  1. TF-IDF与余弦相似性的应用(一):自动提取关键词
  2. 如何进行高效JavaScript单元测试
  3. vim 批量注释代码
  4. PPR 搜索里max hit不起作用
  5. P1136 迎接仪式
  6. shiro学习(13):springMVC结合shiro完成认证
  7. 一个很漂亮的jQuery动画隐藏登陆框,css很漂亮
  8. mktime()的格式
  9. blender 快捷键
  10. 分享一个在沪深300下获得146.56%超额收益的策略
  11. RDS报警问题解决过程
  12. 利用计算机审计新闻,计算机审计显身手 审计员钻出账本堆被审单位麻烦减少...
  13. 并发和并行以及线程安全
  14. 【Flink】搭建单机环境
  15. ArcGIS Desktop、Arcengine、ArcObjects_SDK for NET.Framework安装教程
  16. 圆角 border-radius
  17. 10.5国庆作业(IIC实验)
  18. css动态飞飞荷包蛋
  19. 《菊次郎的夏天》---温情的北野武,诗意的久石让
  20. SketchUp等设计软件官方推荐电脑配置 |干货

热门文章

  1. EasyUi 改变 selelct 的 下拉内容 div 的高度
  2. Linux中perl脚本监控
  3. ORA-00257 解决办法
  4. BufferedReader和PrintWriter读写中文的问题
  5. 【系列】EOS开发1 开发环境搭建
  6. go标准库的学习-sync互斥
  7. 60个开发者不容错过的免费资源库
  8. [bzoj 2434][Noi2011]阿狸的打字机
  9. NSPredicate
  10. 《需求分析与系统设计》阅读笔记三