Java 深入学习字符串equals()和“==”的区别

博主在实际开发过程中,判断界面元素element.getText()与期望值是否相等时,采用==出现判断错误,在网上查阅了很多资料,这里做个总结,记录学习过程。要理解equals和==的区别首先要理解Java内存中的对象和数据是如何存储的。

一、栈、堆以及常量池的概念和区别

任何程序在运行时都要在内存中开辟控件,java运行时虚拟机来做这个事情。

  • 栈(stack):一片内存区域,用来存储局部变量以及对象的引用,数据可以共享,当没有引用指向数据时,数据就会消失
  • 堆(heap):一片内存区域,用来存储所有new出来的对象本身,数据不可以共享,对象由java的垃圾回收器负责处理,内容相同的数据,可以有多份
  • 常量池(public static pool):一片内存区域,用来存储基本类型常量和字符串常量,数据可以共享,内容相同的数据,只有一份

注:全局变量存放在全局数据区;常量池分为静态常量池和运行时常量池,这里指运行时常量池

示例代码test.java如下:

public class test {
	public static void main(String[] args){
		//基本数据类型,n和1都在栈中
		int n=1;
		//常量m,m存储在栈中,1存储在常量池中
		final int m=1;
		//字符串,s1和s2是字符串变量,属于局部变量,在栈中,而“Java”是字符串常量,在常量池中
		String s1="Java";
		String s2="Java";
		//字符串s3是new String("Java")的引用,s3在栈中,new String("Java")在堆中
		String s3=new String("Java");
		//字符串s4同s4,但是又有区别,每new一次,都会开辟新的空间
		String s4=new String("Java");
		System.out.println(s1==s2);//true
		System.out.println(s1==s3);//false
		System.out.println(s3==s4);//false
		System.out.println(s1==s3.intern());//true
	}
}

绿色箭头:1属于基本类型常量,Java属于字符串常量

红色箭头:new String("Java")属于new的新对象,每new一次,就会有新的对象存储在堆中。

蓝色箭头:new产生对象时,先去常量池查找是否有"Java",如果没有,现在常量池创建,再在堆中创建常量池中此"Java"对象的拷贝对象,如果有,常量池就不再创建了;这样也说明常量池中内容相同的只有一份数据;同时也说明new语法产生的对象可能是一个也可能是两个

区别:栈的优势在于读取速度仅次于CPU寄存器,栈的数据可以共享,缺点在于栈中数据的大小和生命周期是确定的,区别于堆,堆的优势在于可以动态的分配内存大小,有垃圾回收机制,代码不必关注生命周期,缺点是读取较慢,数据之间无法共享。

二、基本数据类型和引用数据类型的概念和区别

1、基本数据类型(4类8种)

整数类型:long、int、short、byte

浮点类型:float、double

字符类型:char

布尔类型:boolean

非全局基本数据类型的变量和内容都在存储在栈中,变量名指向具体的值,在声明时立刻就会被分配内存在栈中,互相之间的赋值是创建新的拷贝,创建和销毁都很迅速。

2、引用数据类型

除基本数据类型之外的都是引用数据类型,如类、接口、字符串、枚举等等。

引用数据类型变量,引用即具体内容所在内存的地址存储在栈中,具体内容存储在堆中,变量名指向对象的内存地址,在声明时只是在引用中存储了一个内存地址,互相之间的赋值只是传递引用,对象的销毁需要JVM虚拟机的回收机制实现。

三、字符串equals()和"=="的实质性区别

String类是继承自Object基类,对其中的equals方法进行了重写,Object基类里面equlas和"=="一样都是比较两边的地址值是否相同,而String类的equals方法重写之后是比较两边的值是否相等。String类的equals源码如下:

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String aString = (String)anObject;
            if (coder() == aString.coder()) {
                return isLatin1() ? StringLatin1.equals(value, aString.value)
                                  : StringUTF16.equals(value, aString.value);
            }
        }
        return false;
    }

通过前两节的介绍,字符串是引用数据类型。采用直接定义的字符串属于字符串常量,采用String类new出来的字符串属于对象。引用数据类型在栈和堆中分别存储引用和具体内容,字符串常量存储在常量池中,new出来的对象存储在堆中。

equals和"=="区别示例代码如下:

public class test {
	public static void main(String[] args){
		//常量
		final String s1="hello";
		final String s2="Java";
		//直接定义字符串,字符串常量
		String s4="hello";
		String s5="Java";
		String s6="helloJava";
		//通过String类定义对象的方式定义字符串
		String s9=new String("helloJava");
		String ss=new String("helloJava");
		//字符串对象相加,字符串本身相加
		String s10=s4+s5;
		String s11="hello"+"Java";
		//常量字符串相加
		String s12=s1+s2;
		//s10实际上是由s4和s5两个对象相加,过程会有new的动作
		System.out.println(s6==s10);//false
		System.out.println(s6.equals(s10));
		System.out.println(s6==s11);//true
		// final常量类型相加,初始化是常量
        // 这里是final关键字的作用,s1和s2会被当做编译器常量,类似C语言的宏
        // 如果s1变为 final String s1 = getHello(); 就不是在编译器知道的,而是在运行期才知道s1具体的值,这样的话下面的值就会变成false
		System.out.println(s6==s12);//true
		//new一次,新的对象,==对比值,equals对比内容
		System.out.println(s9==ss);//false
		System.out.println(s9.equals(ss));//true
	}
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值