Java中==与equals()方法的区别

== :   

比较的是两个变量的值是否相等.

基本数据类型 : 变量直接存储的是值,数值相等,则返回true;

引用数据类型 : 变量存储的是其指向的对象在内存中存储的地址,并非指向的对象所存储的内容.

Ps:对于引用数据类型的比较时,String中存在字符串常量池,“使用常量池”对应的字节码是一个 ldc 指令,在给 String 类型的引用赋值的时候会先执行这个指令,看常量池中是否存在这个字符串对象的引用,若有就直接返回这个引用,若没有,就在堆里创建这个字符串对象并在字符串常量池中记录下这个引用.JVM 中除了字符串常量池,8种基本数据类型中除了两种浮点类型剩余的6种基本数据类型的包装类,都使用了缓冲池技术,但是 Byte、Short、Integer、Long、Character 这5种整型的包装类也只是在对应值在 [-128,127] 时才会使用缓冲池,超出此范围仍然会去创建新的对象。

所以,String变量会先从常量池中找,若没有则存储在常量池中,若有,则指向常量池中已存在的值,故:String str1="aa";String str2="aa";System.out.println(str1==str2);会输出true.

然而String str1=new String("111");String str2=new String("111");System.out.println(str1==str2);会输出false,原因是该出是new的两个不同的对象,开辟了两块空间,指向的内存地址值不同,故输出false.

扩展阅读:

Integer类型和int类型相等的值是否相等? - Java

来自黑马视频​​

 

equals :

equals()方法存在于Object类中,所有类继承自Object类,Object类中equals()比较的是两个变量指向的对象在内存中存储的地址是否相等.所以对于未重写equals方法的类,比较的都是对象在内存中存储的地址.

//Object类中equals方法源码
public boolean equals(Object obj) {
        return (this == obj);
    }

 

对于String,Integer,Double,Long..等包装类,List,Set,Map类等等中的equals方法,都重写了equals方法,因为这些类都是Object的子类,根据多态的特征,这些类调用equals方法时是调用子类(即本身)的equals方法.这些类中的equals方法比较的是两个变量所指向的对象中存储的值是否相等.

//String类中的equals方法源码
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;
    }

在HashTable或HashMap类中,重写equals()方法时,一定要重写hashCode方法!

       如果你用自定义的类当作key的话,要相当小心,按照散列函数的定义,如果两个对象相 同,即obj1.equals(obj2)=true,则它们的hashCode必须相同,但如果两个对象不同,则它们的hashCode不一定不同,如 果两个不同对象的hashCode相同,这种现象称为冲突,冲突会导致操作哈希表的时间开销增大,所以尽量定义好的hashCode()方法,能加快哈希 表的操作。
  如果相同的对象有不同的hashCode,对哈希表的操作会出现意想不到的结果(期待的get方法返回null),要避免这种问题,只需要牢记一条:要同时复写equals方法和hashCode方法,而不要只写其中一个。 

 

重写equals方法的建议

  1. 显示参数命名为otherObject, 稍后需要将他转换成另一个叫做other的变量.
  2. 检测this与otherObject是否引用同一个对象 : if (this == otherObject) return true;
  3. 检测otherObject是否为null, 如果为null, 返回false : if (otherObject == null) return false;
  4. 比较this与otherObject是否属于同一个类. 如果equals的语义在每个子类中有所改变,就使用getClass检测 : if (getClass() != otherObject.getClass()) return false; 如果所有的子类都拥有统一的语义,就使用instanceof检测 : if (!(otherObject instanceof ClassName)) return false;
  5. 将otherObject转换为相应的类类型变量 : ClassName other = (ClassName) otherObject;
  6. 现在开始对所有需要比较的与进行比较了. 使用 == 比较基本类型域, 使用 equals 比较对象与.如果所有的域都匹配, 就返回true;否则返回false.
    @Override
    public boolean equals(Object otherObject) {
        if (this == otherObject) {
            return true;
        }

        if (otherObject == null) {
            return false;
        }

        if (getClass() != otherObject.getClass()) {
            return false;
        }

        Employee other = (Employee) otherObject;

        return Objects.equals(name, other.name) && salary == other.salary
                && Objects.equals(hireDay, other.hireDay);
    }

 如果在子类中重新定义equals,就要在其中包含调用super.equals(other).

     @Override
    public boolean equals(Object otherObject) {
        if (!super.equals(otherObject)) {
            return false;
        }

        Manager other = (Manager) otherObject;

        return bonus == other.bonus;
    }

--摘自<Java核心技术卷一>

 

举例:

import java.util.ArrayList;
import java.util.List;

public class Main{
	public static void main(String[] args) {
		int a1 = 2;
		int a2 = 2;
		String str1 = "111";
		String str2 = "111";
		String str3 = str1;
		/*
		 * ==的比较
		 * 
		 */
		System.out.println(a1 == a2);// 基本数据类型的比较 结果为:true
		System.out.println(str1 == str2);// 引用数据类型的比较 结果为:true 
		           					   	 // 原因:用到了常量池,创建的第一个对象存储在常量池中,
	                                  	 // 第二个对象引用时会先从常量池中找看是否存在,存在则指向常量池中对象的内存地址
		System.out.println(str3 == str1);// 结果为:true

		String s1 = new String("111");
		String s2 = new String("111");
		System.out.println(s1 == s2);// 结果为:false 原因:两个变量引用的对象的地址值不同
		/*
		 * Object中equal方法
		 */
		Object obj1 = "abc";
		Object obj2 = "abc";
		System.out.println(obj1.equals(obj2));// 结果为:true 原因:与常量池道理类似
		Object ob1 = new Object();
		Object ob2 = new Object();
		System.out.println(ob1.equals(ob2));// 结果为:false 原因:两个变量引用的对象的地址值不同
		ob1 = "12";
		ob2 = "12";
		System.out.println(ob1.equals(ob2));// 结果为:true 原因:尽管开辟了两块地址空间,但又都指向了一个"12"的内存地址.

		Integer in1 = 1;
		Integer in2 = 1;
		System.out.println(in1 == in2);// 结果为:true 原因:存在缓冲区,缓冲大小为[-128,127]
		Integer inte1 = -129;
		Integer inte2 = -129;
		System.out.println(inte1 == inte2);//结果为:false 原因:超出了缓冲区的范围
		/*
		 * 重写的equals方法
		 */
		// 输出都为true.因为这些类都重写了equals方法,比较的是引用对象所存储的内容
		System.out.println(str1.equals(str2));
		Integer i = new Integer(2);
		Integer i1 = new Integer(2);
		System.out.println(i.equals(i1));
		List list1 = new ArrayList(1);
		List list2 = new ArrayList(1);
		System.out.println(list1.equals(list2));
	}
}

 

摘自:https://blog.csdn.net/ooppookid/article/details/51487797

String在内存中如何存放?

String str = new String( "abc" );
String str = "abc" ;

第一种是用new()来新建对象的,它会在存放于堆中,每调用一次就会创建一个新的对象。 
第二种是先在栈中创建一个对String类的对象引用变量str,然后查找运行时常量池中有没有存放”abc”,如果没有,则将”abc”存放进常量池,并令str指 向”abc”,如果已经有”abc” 则直接令str指向”abc”。

常量池在方法区内,用来存放基本类型包装类(包装类不管理浮点型,整形只会管理-128到127)和String(通过String.intern()方法可以强制将String放入常量池)。

intern

public String intern()

返回字符串对象的规范表示。

最初为空的字符串池由StringString

当调用intern方法时,如果池已经包含与equals(Object)方法确定的相当于此String对象的字符串,则返回来自池的字符串。 否则,此String对象将添加到池中,并返回对此String对象的引用。

由此可见,对于任何两个字符串sts.intern() == t.intern()true当且仅当s.equals(t)true

所有文字字符串和字符串值常量表达式都被实体化。 字符串文字在The Java™ Language Specification的 3.10.5节中定义。

结果

一个字符串与该字符串具有相同的内容,但保证来自一个唯一的字符串池。

 


[参考文章]

Kingram              : Java内存中的常量池

千古壹号             : Java语法----Java中equals和==的区别

Matrix海子          : 浅谈Java中的equals和==

安东尼_Anthony : Java 重写Object类的常见方法-equals和hashCode

@ 小浩               : java中的基本数据类型一定存储在栈中吗?

lockemn             : Java数据存储

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值