java中==
和equals
的分析
1.java中==
和equals()
方法介绍
-
==
一般用来比较两个基本数据类型变量(局部变量)的值是否相等。如果用于比较引用数据类型的变量,也是比较变量的值,不同的是,引用数据类型变量存储的是数据的首地址(即数据在堆中存放的地址),所以是地址的比较。- Java中的8种基本数据类型:
- 整型4种:byte(1字节),short(2字节),int(4字节),long(8字节)
- 浮点型2种:float(4字节),double(8字节)
- 字符型1种:char(2字节)
- 布尔型1种:boolean(1bit)
- Java中的引用数据类型:
- 类(包含String)
- 接口
- 数组
- Java中的8种基本数据类型:
-
equals()
方法一般用于两个对象的内容是否相等。内容即变量所存储的地址指向的数据,在堆中。- 例如:比较String类的对象
String str1 = new String("happy")
和String str2 = new String("happy")
是否相等 - 用
==
比较str1
和str2
的结果是false
,用equals()
方法比较结果是true。
- 例如:比较String类的对象
2.Java中的数据类型在内存中的存储原理
-
在方法中声明的变量,称为局部变量;在类中声明的变量是成员变量,也叫全局变量。
- 对于局部变量来说,不论是基本数据类型还是引用类型,他们都会先在栈中分配一块内存,对于基本类型来说,这块区域包含的是基本类型的内容;而对于引用类型来说,这块区域包含的是指向真正内容的指针,真正的内容被手动的分配在堆上。
- 对于成员变量来说,不论是基本数据类型还是引用类型,他们都会存储在堆内存或者方法区中;成员变量可细分为静态成员变量和普通成员变量,静态成员变量属于类,类可以直接访问,存储在方法区中;普通成员变量属于类对象,必须声明对象之后,通过对象才能访问,存储在堆中。
3.java中==
和equals()
适用范围举例分析
3.1 比较java基本数据类型
-
比较java基本数据类型:
-
对于8种基本数据类型(byte,short,char,int,float,double,long,boolean)
-
只能用
==
,不能用equals()
(单纯的变量也无法调用equals()方法),这里的==
比较的是两个基本类型的值 -
int i1 = 2; int i2 = 2; double d1 = 2.2; double d2 = 2.2; char ch1 = 'b'; char ch2 = 'b'; if(i1 == i2 && d1 == d2 && ch1 == ch2 ){ System.out.println("flag1 = " + true);//flag1 = true }else{ System.out.println("flag1 = " + false); }
-
3.2 比较java基本数据类型的包装类型
-
比较java基本数据类型的包装类型:
-
对于基本数据类型的包装类型(Byte, Short, Character,Integer,Float, Double,Long, Boolean)
-
属于引用数据类型,用
equals()
-
除了Float和Double之外,其他的六种都是实现了常量池的,因此对于这些数据类型而言,一般也可以直接通过
==
来判断是否相等。 -
Integer int1 = new Integer(127); Integer int2 = new Integer(127); Integer int3 = new Integer(128); Integer int4 = new Integer(128); System.out.println("int1 == int2?"+ (int1 == int2));//int1 == int2?true System.out.println("int3 == int4?"+ (int3 == int4));//int3 == int4?false System.out.println("int3.equals(int4) ?"+ (int3.equals(int3)));//int3.equals(int4) ?true
-
int1 == int2?true
:因为127在常量池中,在给int1
和int2
赋值的时候,指向的是同一个地址,所以变量存储的地址相等。 -
int3 == int4?false
: Integer 在常量池中的存储范围为[-128,127],则128不在常量池中,在给int3
和int4
赋值的时候,会在堆内存中分别创建两个对象来保存,所以变量存储的地址不等。 -
int3.equals(int4) ?true
: Integer类的equals()
方法是比较的变量存储的地址所指向的内容,见其实现方法: -
/** * Compares this object to the specified object. The result is * {@code true} if and only if the argument is not * {@code null} and is an {@code Integer} object that * contains the same {@code int} value as this object. * * @param obj the object to compare with. * @return {@code true} if the objects are the same; * {@code false} otherwise. */ public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }
-
3.3 比较比较字符串String
-
比较字符串
String
-
==
比较的是内存地址,equals
比较的是值 -
String str1 = "happy"; String str2 = "happy"; System.out.println("str1 == str2? "+ (str1 == str2));//str1 == str2? true String objStr1 = new String("like"); String objStr2 = new String("like"); System.out.println("objStr1 == objStr2? "+ (objStr1 == objStr2)); //objStr1 == objStr2? false System.out.println("objStr1.equals(objStr2)? "+ (objStr1.equals(objStr2))); //objStr1.equals(objStr2)? true
-
str1 == str2? true
:String str2 = "happy"
的实现过程中,指向的是和str1
相同的对象。即str1
和str2
c存储是同一个地址,所以用==
判断的结果是true
. -
objStr1 == objStr2? false
:String objStr2 = new String("like")
的实现过程中,会生成新的对象。即str1
和str2
c存储是不同的地址,所以用==
判断的结果是false
. -
objStr1.equals(objStr2)? true
:比较的是变量存储地址所指向的内容,所以用equals()
判断的结果是true
:/** * Compares this string to the specified object. The result is {@code * true} if and only if the argument is not {@code null} and is a {@code * String} object that represents the same sequence of characters as this * object. * * @param anObject * The object to compare this {@code String} against * * @return {@code true} if the given object represents a {@code String} * equivalent to this string, {@code false} otherwise * * @see #compareTo(String) * @see #equalsIgnoreCase(String) */ public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
-
-
java中String 和 new String()的区别:
- String str1 = "happy"的实现过程:首先栈区创建str引用,然后在String池(独立于栈和堆而存在,存储不可变量)中寻找其指向的内容为"happy"的对象,如果String池中没有,则创建一个,然后str指向String池中的对象,如果有,则直接指向;后来定义了字符串变量 str2 = “happy”,则直接将str2引用指向String池中已经存在的“happy”,不再重新创建对象。
- 当str1进行了赋值(str1=“happ”),则str1将不再指向"happy",而是重新指String池中的"happ",此时如果定义String str3 = “happ”,进行str1 == str3操作,返回值为true,因为他们的值一样,地址一样,但是如果内容为"happ"的str1进行了字符串的+连接str1 = str1+“y”;此时str1指向的是在堆中新建的内容为"happy"的对象,即此时进行str1==str2,返回值false,因为地址不一样。
- String str3 = new String(“abcd”)的实现过程:直接在堆中创建对象。如果后来又有String str4 = new String(“abcd”),str4不会指向之前的对象,而是重新创建一个对象并指向它,所以如果此时进行str3==str4返回值是false,因为两个对象的地址不一样,如果是str3.equals(str4),返回true,因为内容相同。
- String str1 = "happy"的实现过程:首先栈区创建str引用,然后在String池(独立于栈和堆而存在,存储不可变量)中寻找其指向的内容为"happy"的对象,如果String池中没有,则创建一个,然后str指向String池中的对象,如果有,则直接指向;后来定义了字符串变量 str2 = “happy”,则直接将str2引用指向String池中已经存在的“happy”,不再重新创建对象。
3.4 比较一般对象
-
比较一般对象:
-
==
比较的是内存地址,equals()
比较的也是地址 -
一般对象没有重写
equals()
方法,默认调用对象Object
的equals()
:/** * Indicates whether some other object is "equal to" this one. * <p> * The {@code equals} method implements an equivalence relation * on non-null object references: * <ul> * <li>It is <i>reflexive</i>: for any non-null reference value * {@code x}, {@code x.equals(x)} should return * {@code true}. * <li>It is <i>symmetric</i>: for any non-null reference values * {@code x} and {@code y}, {@code x.equals(y)} * should return {@code true} if and only if * {@code y.equals(x)} returns {@code true}. * <li>It is <i>transitive</i>: for any non-null reference values * {@code x}, {@code y}, and {@code z}, if * {@code x.equals(y)} returns {@code true} and * {@code y.equals(z)} returns {@code true}, then * {@code x.equals(z)} should return {@code true}. * <li>It is <i>consistent</i>: for any non-null reference values * {@code x} and {@code y}, multiple invocations of * {@code x.equals(y)} consistently return {@code true} * or consistently return {@code false}, provided no * information used in {@code equals} comparisons on the * objects is modified. * <li>For any non-null reference value {@code x}, * {@code x.equals(null)} should return {@code false}. * </ul> * <p> * The {@code equals} method for class {@code Object} implements * the most discriminating possible equivalence relation on objects; * that is, for any non-null reference values {@code x} and * {@code y}, this method returns {@code true} if and only * if {@code x} and {@code y} refer to the same object * ({@code x == y} has the value {@code true}). * <p> * Note that it is generally necessary to override the {@code hashCode} * method whenever this method is overridden, so as to maintain the * general contract for the {@code hashCode} method, which states * that equal objects must have equal hash codes. * * @param obj the reference object with which to compare. * @return {@code true} if this object is the same as the obj * argument; {@code false} otherwise. * @see #hashCode() * @see java.util.HashMap */ public boolean equals(Object obj) { return (this == obj); }
Object
类是所有类的直接或间接父类,也就是说所有的类中的equals()
方法都继承自Object类,而通过上面的源可发现,Object
类中equals()
方法底层依赖的是==
号,那么,在所有没有重写equals()
方法的类中,调用equals()
方法其实和使用==
号的效果一样,也是比较的地址值,然而,Java提供的所有类中,绝大多数类都重写了equals()
方法,重写后的equals()
方法一般都是比较两个对象的值。例如前面提到的String
和Integer
。
-
参考: