JAVA 学习分享之 ‘’==”、“equals()“和“Integer“的奇妙碰撞

545 阅读4分钟

「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战

前言

今天在刷lc算法题时,刷到一道算法题,题目不难但是在用代码解决问题的时候发生了一个有趣的问题也是比较基础的引用数据类型和基本类型值比较问题以及Integer的特殊IntegerCache。

题目是:剑指 Offer 30. 包含min函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。

示例:

 MinStack minStack = new MinStack();
 minStack.push(-2);
 minStack.push(0);
 minStack.push(-3);
 minStack.min();   --> 返回 -3.
 minStack.pop();
 minStack.top();      --> 返回 0.
 minStack.min();   --> 返回 -2.

下面给出我的解题代码(参考大佬思路):

 class MinStack {
 ​
     /** initialize your data structure here. */
     Stack<Integer> stackA,stackB;
     public MinStack() {
         stackA = new Stack<>();
         stackB = new Stack<>();
     }
     
     public void push(int x) {
         stackA.push(x);
         if(stackB.isEmpty() || stackB.peek() >= x){
             stackB.push(x);
         }
     }
     
     public void pop() {
         if(stackA.pop() == stackB.peek()){
             stackB.pop();
         }
     }
     
     public int top() {
         return stackA.peek();
     }
     
     public int min() {
         return stackB.peek();
     }
 }
 ​
 /**java
  * Your MinStack object will be instantiated and called as such:
  * MinStack obj = new MinStack();
  * obj.push(x);
  * obj.pop();
  * int param_3 = obj.top();
  * int param_4 = obj.min();
  */

解题思路:

使用两个栈,stackA和stackB,其中stackA存所有元素,stackB存最小元素(递减顺序,最小元素保持在栈顶)。

栈A,全部push进去

栈B,如果栈B是空的就push,如果栈B不为空,判断当前元素是否小于栈顶元素,如果小于等于就push,否则就不push到栈B。

min()函数调用就取B栈栈顶,pop()函数就将A栈顶元素弹出,同时判断栈顶元素是否等于B栈栈顶元素,等于的话B栈栈顶也要弹出,与A栈元素保持同步。

按照上面的思路,很快就实现了代码并且测试执行通过了。

测试用例:

 ["MinStack","push","push","push","min","pop","top","min"]
 [[],[-2],[0],[-3],[],[],[],[]]

但是当我点击提交运行,结果却是有5个用例未通过。

image-20220212172804014.png

于是我看了看题解大佬的代码,好像没什么不一样啊。再仔细观察,发现了不同之处在pop()方法的==之处,大佬的代码使用了equals(),我恍然大悟。

==equals()区别

首先我们知道,==和equals在做比较时是有区别的

==

  1. 基本类型比较是值的比较

  2. 一边是包装类型一边是基本类型时:

    同类型的进行比较,如Integer 与int,Long与long进行==比较时,会自动拆箱比较值

    不同类型之间进行比较,则会自动拆箱,且会进行自动向上转型再比较值

  1. 两边都是包装类型则直接比较引用地址,但IntegerCache除外。

    JAVA的Integer有IntegerCache会缓存-128~127之间的对象,可以通过-Djava.lang.Integer.IntegerCache.high=值修改

    看一下Integer.valueOf()方法的代码

      public static Integer valueOf(int i) {
             if (i >= IntegerCache.low && i <= IntegerCache.high)
                 return IntegerCache.cache[i + (-IntegerCache.low)];
             return new Integer(i);
         }
    

image-20220212174548208.png equals()

  1. 基本类型(值类型)之间无法使用equals比较。
  2. equals参数为值类型,则参数会进行自动装箱为包装类型。
  3. equals参数为包装类型,则先比较是否为同类型,非同类型直接返回false,同类型再比较值。

Integer的比较

下面看具体例子:

 Integer a = 10;
 Integer b = 10;
 System.out.println(a==b);
 System.out.println(a.equals(b));

输出为:

true

true

下面看这段代码

 Integer a = 10;
 Integer b = 10;
 Integer c = Integer.valueOf(10);
 Integer d = new Integer(10);
 ​
 System.out.println(a==d);
 System.out.println(c==d);
 System.out.println(c.equals(d));

输出:

false

false

true

为什么c==d输出为false呢?,因为包装类型的时候==比较的是引用地址,d是new 的对象,所以地址肯定不相同。

下面这段代码

 Integer a = 128;
 Integer b = 128;
 ​
 System.out.println(a==b);
 System.out.println(a.equals(b));

输出:

false

true

IntegerCache默认的范围是-127 - 127,所以a==b比较引用为false。

Integer.valueOf()和Integer.parseInt()

Integer.valueOf()返回的是一个Integer对象

Integer.parseInt()返回的是一个基本类型的int

parseInt()如果使用Integer接收返回值,会自动装箱。

valueOf()如果使用int类型接收返回值则会自动拆箱。

两则都有缓存IntegerCache

 Integer a = Integer.parseInt("127");
 Integer b = Integer.valueOf("127");
 ​
 System.out.println(a==b);

输出:true

最后

相信看到这里大家已经知道为什么使用==时,部分用例也能过了吧,在以后的工作中对于引用数据类型的比较一定严格使用equals()。

以上就是今天的学习分享,欢迎大家发表观点,指出不足。