判断对象是否相等与数值对象的拆箱与封箱

前言:

        最近,因为一个问题看了前人写的代码,简单思考,给我整懵了。伪代码如下:

        ArrayList list = new ArrayList<>();
        Long long1= new Long(20230228250111L);
        list.add(20230228250111L);
        list.add(20230228250222L);
        list.add(20230228250333L);
        // 判断集合中是否存在该值
        System.out.println(list.contains(long1.longValue()));

        前人在调用contains()时,使用long1对象的基本数据类型去判断。我当时看完这个代码后,我感觉厉害啊,他一定考虑到数值类型的拆箱与封箱对判断对象是否相等影响的问题。但是,我深入思考一下,这样写多此一举。

正文:

        我先简单介绍一下拆箱与封箱。以Integer与int为例:int类型值转换成Integer对象,这个过程叫做装箱;将Integer对象转换成int类型值,这个过程叫做拆箱;装箱和拆箱是自动进行的,非人为转换。

        为什么要有这个机制?我看过一种说法是,Java早年设计缺陷。基础类型是数据,不是对象,也不是Object的子类。需要把一个基本类型包装成一个类,然后再使用。大家都知道Java的核心就是万物切实对象。

        判断对象是否相等,有两种方法:==和equals。使用equals判断对象是否相等,需要对象重写equals()和hashCode()。使用==判断对象是否相等,一般只能用于基本数据类型的比较。==比较的是内存地址。但是,不同数值类型的拆箱与封箱会缓存一定范围的值,避免重复创建对象,例如Integer缓存了-128到127的数值。在Integer使用==时,会有如下几个规则:

  • 1. Integer与new Integer不会相等;
  • 2. 两个都是非new出来的Integer,如果数在-128到127之间,则是true,否则为false;
  • 3. 两个都是new出来的Integer,都为false;
  • 4. int和Integer(无论是否new)比,都为true,因为会把Integer自动拆箱为int再去比。

        介绍完相关知识后,咱们再看一下前人的代码,主要看一下contains()底层实现:

        public boolean contains(Object o) {
            return indexOf(o) >= 0;
        }

        public int indexOf(Object o) {
            if (o == null) {
                for (int i = 0; i < size; i++)
                    if (elementData[i]==null)
                        return i;
            } else {
                for (int i = 0; i < size; i++)
                    if (o.equals(elementData[i]))
                        return i;
            }
            return -1;
       }

        通过源码,我们了解到contains()是通过遍历集合中元素,通过equals()判断对象是否相等。集合中对象的数据类型是Long,Long类型的equals()源码如下:

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

        Long类型的equals()使用的是==,但是,双方已经使用基本数据类型比较了。所以,根本就不需要再判断是否相等时,使用long1.longValue(),有点多此一举

你可能感兴趣的:(java)