比较两个值是否相等

判断两个对象是否相等时,有两种方法,==equals()

  • == : 它的作用是判断两个对象的地址是不是相等。对于基本类型,比较的是值,对于对象,比较的是对象的存放地址。

  • equals() : 它的作用也是判断两个对象是否相等。

    • 如果类中覆盖了该方法,那么通常是比较两个对象的内容是否相等。如果相等,则返回 true;如果不等,则返回 false
    • 如果类中没有覆盖该方法,那么比较的是两个对象的地址是否相等,等价于==

在举例子之前,先说一下基本类型和包装类型的东西。

1. 基本类型和包装类型

1.1 包装类型

基本类型有8种,都有各自的默认值,默认值均不为null,分别是:

  • 6 种数字类型 :byteshortintlongfloatdouble

  • 1 种字符类型:char

  • 1 种布尔型:boolean

1.2 包装类型

包装类型是基本类型所对应的对象。由于包装类型是对象,所以可以用于泛型,

1.3 信息总结

这 8 种基本数据类型的默认值以及所占空间的大小如下:

基本类型位数字节默认值对应的包装类型包装类的默认值
数字型short1620Shortnull
int3240Integernull
long6480LLongnull
字符型byte810Bytenull
char162‘u0000’Characternull
数字型float3240fFloatnull
double6480dDoublenull
布尔型boolean1FALSEBooleannull

1.4 在哪里放着

  • 基本类型的局部变量在栈中的局部变量表中存放,基本类型的成员变量在堆中存放。

  • 包装类型是对象类型,几乎所有的对象类型都在中。

Alt

小纸条

如果类中成员变量使用基本类型(如 int),并且不被static修饰的话,会存放在堆中。

这种情况,使用基本类型对应的包装类型更好。

class Student {
    private int age;
}

// 改为包装类型
class Student {
    private Integer age;
}

1.5 包装类型的缓存机制

包装类型会用缓存机制来提高性能。各个包装类型的缓存能数据范围如下:

包装类型缓存数据范围
数字型Short[ -128, 127 ]
Integer[ -128, 127 ]
Long[ -128, 127 ]
字符型Byte[ -128, 127 ]
Character[ 0, 127 ]
布尔型Booleantrue / false

如果要创建的包装类型的数据在缓存中能找到,那么会直接使用缓存中的数据,而不会创建新的对象。比如

Integer i1 = 10;    // 10 < 127,i1使用缓存中的数据
// 判断 i1 的情况
// 如果 i1 使用缓存中的数据,没有创建新对象,那么再创建一个值为10的对象,
// 两个对象的地址应该是相同的,都是缓存中的数据的地址
Integer i12 = 10;
System.out.println(i1 == i12);   // 输出结果为 true    

Integer i2 = 128;    // 128 > 127,i2创建新的对象
// 判断 i2 的情况
// 如果 i2,创建了新对象,没有使用缓存中的数据,那么再创建一个值为128的对象,
// 两个对象的地址应该是不同的,因为两个对象的地址不会相同
Integer i22 = 128;
System.out.println(i2 == i22);    // 输出结果为 false  

1.6 自动拆箱与装箱

自动装箱和拆箱,是自动在基本类型和包装类型之间进行转换,这种转换是在赋值、方法调用时等情况下发生的,比如

// 基本类型 转为 包装类型
Integer a = 200;   
// 200是基本类型,但是可以直接赋给 Integer 变量a ,而不用进行类型转换
// 如果没有自动装箱,就只能使用 Integer a = new Integer(200); 来创建变量
 
// 基本类型 转为 包装类型
int b = a;    // a 是包装类型,但是可以直接赋给int类型 ,而不用进行类型转换
// a 是 Integer类型,b 是 int 类型,如果没有自动拆箱,就需要自己进行类型转换
自动拆箱和装箱,是在本来需要自己进行类型转换的时候,交给Java进行,而不用自己强制转换。

2. 比较

  • 基本类型和基本类型比较,使用 == 即可。

  • 基本类型和包装类型比较,使用 ==

  • 对象和对象比较,使用equal()

2.1 数字比较

基本类型和基本类型比较,比较的是值是否相等。

int a = 10;
int b = 10;    // b == a
int c = new Integer(10);    // c == a

基本类型和包装类型比较,比较的也是值是否相等。

int a = 10;
Integer aa = new Integer(10);    // aa == a

包装类型和包装类型比较,比较的是地址是否相等。

Integer a = new Integer(10);
Integer b = new Integer(10);    // b != a,不是同一个对象,地址不同

2.2 String 比较

String是一个常量,存放在运行时常量池(在方法区/元空间)。是不可变的(在创建之后无法更改),它的底层是由char[]实现的。比如:

String str = "abc";
// 等价于
char[] data = {'a', 'b', 'c'};
String str = new String(data);

由于String对象是不可变的,所以它们是可以被共享的。在创建新的String对象时,如果常量池中存在该对象的值,那么不会创建新的字符串,而是会直接使用常量池中存在的字符串。如果常量池中不存在该对象的值,那么会在常量池中创建字符串。

所以,比较两个类型为 String 的字符串是否相等,最好使用equals()

// 使用常量池的数据
String s1 = "abc";    // 在常量池中创建一个 abc 字符串
String s2 = "abc";    // 使用常量池中的数据
System.out.println(s1 == "abc");    // true。s1 和 "abc" 的地址相同
System.out.println(s2 == "abc");    // true。s2 和 "abc" 的地址相同
System.out.println(s1 == s2);    // true。s1 和 s2 指向的是同一个对象
System.out.println(s1.equals(s2));    // true.s1 和 s3 的值相等

// 使用 new 创建新对象
String s3 = new String("abc");    // 创建一个新对象
System.out.println(s3 == "abc");    // false。s3 和 "abc" 的地址相同,s3 使用的不是常量池中的数据
System.out.println(s3 == s1);    // false。s1 和 s3 不是一个对象
System.out.println(s1.equals(s3));    // true。s1 和 s3 的值相等

String s4 = "def";    // 在常量池中创建一个 def 字符串
System.out.println(s1 == s4);

字符串和对象引用的示意图如下:
字符串和对象引用

2.3 对象比较

比较两个对象的地址是否相同,如果相同则返回 true,如果不同则返回 false

// 创建一个 Integer 对象
Integer a = new Integer(10);
// 使用两个变量作为对比
Integer b = new Integer(10);    // b != a,不是同一个对象
Integer c = a;    // c == a,是同一个对象

对象和对象引用的示意图如下:
字符串和对象引用

3. HashMap相关

由于 HashMap要说的内容和上面的比较情况稍有不同,这里把 HashMap中想要说的东西单独拎出来。

1)containsKey()

HashMap中常常需要判断某个值是否在HashMap中,会用到containsKey()。该方法判断某个值在HashMap中是使用equals()来判断的, 也就是说,如果一个类覆盖了这个方法,那么是并根据值来判断的;如果一个类没有覆盖这个方法,那么是根据地址来判断的。

containsKey()有说到,key==null ? k==null : key.equals(k)(其中,keyHasMap中的键,k是要差值的值)当哈希表中键不为空并且等于其中一个键值时,返回true。简短的看,containsKey()就是使用 equal()方法比较keyk是否相等。

举个String例子:

Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);

String s = new String("a");    // 创建一个对象
// 比较的是s和map中的键值是否有相等的。因为String重写了 equals() 方法
System.out.println(map.containsKey(s));  // true

举个一维数组的例子:

Map<int[], Integer> map = new HashMap<>();
map.put(new int[]{1, 2}, 1);
map.put(new int[]{2, 3}, 2);
map.put(new int[]{3, 4}, 2);

int[] array = new int[]{1, 2};    // 创建了一个新数组
// 比较的是array和map中的键值的地址是否有相等的。因为 int[]没有重写 equals()方法
System.out.println(map.containsKey(array));    // false

小纸条

如果需要比较两个数组是否相等时,需要使用 Arrays类的 equals()方法,比如

int[] array1 = {1, 2};
int[] array2 = {1, 2};
Arrays.equals(array1, array2);  // true
2)value比较时的一个情况

值value 和 基本类型比较

先说一种比较常见的情况,我们在创建一个 HashMap对象为 map1后,有时会需要比较 HashMap中是否包含某个值,一般使用 containsValue() 判断是否数据包含在 HashMap中(containsValue()的使用和 containsKey()类似)。比如

Map<Character, Integer> map1 = new HashMap<>();
map1.put('a', 1);
map1.put('b', 200);
// 一般使用 containsValue() 判断是否数据包含在 HashMap 中。比如
System.out.println(map1.containsValue(1));     // true
System.out.println(map1.containsValue(200));     // true

为了说明下一步的例子,这里使用 == 进行比较,给出比较的结果比如

Map<Character, Integer> map1 = new HashMap<>();
map1.put('a', 1);
map1.put('b', 200);
// 但是为了说明下面的例子,这里使用 == 进行比较,比如
System.out.println(map1.get('a') == 1);    // true
System.out.println(map1.get('b') == 200);   // true

这里,map.get()得到的数据类型是Integer,在和基本类型 int比较时,相当于两个基本类型int比较,比的是值是否相等。

值value 和 包装类型比较

下面说的一种情况,我不知道什么时候用到是合适的,一个朋友遇到时,也是挺想不到的。

创建一个 HashMap对象为 map1,存储一些数据。

创建另一个 HashMap对象为 map2,存储和map1相同的数据。

Map<Character, Integer> map1 = new HashMap<>();
map1.put('a', 1);
map1.put('b', 200);
// 创建另一个 HashMap ,存储相同的数据
Map<Character, Integer> map2 = new HashMap<>();
map2.put('a', 1);
map2.put('b', 200);
// 比较
System.out.println(map2.get('a') == map1.get('a'));    // true
System.out.println(map2.get('b') == map1.get('b'));    // false
// 如果要比较,需要使用 equals() 
System.out.println(map2.get('a').equals(map1.get('a')));    // true
System.out.println(map2.get('b').equals(map1.get('b')));    // true

这里出现这样的结果,是一个对象和一个对象的比较(本章2.1),比较的是map中存储对象的地址是否相等。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值