【Java】深层次解析字符串比较

简介: 【Java】深层次解析字符串比较

1. 字符串创建

在我们的JVM中,有常量池-存放字符串、堆-存放new的字符串、栈-存放引用地址

我们看一下创建字符串的两种方式:

String s1 = "china";
        String s2 = "china";
        String s3 = "china";
        String ss1 = new String("china");
        String ss2 = new String("china");
        String ss3 = new String("china");
  • 对于第一种创建:在我们的常量池中创建出一个"china"的字符串,在栈中将s1、s2、s3指向其常量池
  • 对于第二种创建:首先去我们的常量池中寻找有没有"china"字符串,没有则创建,再去我们的堆进行对象的创建,在栈中将ss1、ss2、ss3指向堆中

2. 字符串比较

2.1 普通比较

String str1 = "a";
    String str2 = "b";
    String str3 = "ab";
    String str4 = str1 + str2;
    String str5 = new String("ab");
    String str6 = "a" + "b";
    System.out.println(str5.equals(str3));
    System.out.println(str5 == str3);
    System.out.println(str4 == str3);
    System.out.println(str5.intern() == str3);
    System.out.println(str5.intern() == str4);
    System.out.println(str5.intern() == str6);
    System.out.println(str3 == str6);

先想想自己的答案:

依次分析:

首先看下创建的过程

  1. String str1 = "a"; 直接常量池创建"a",栈创建str1指向
  2. 同上
  3. 同上
  4. String str4 = str1 + str2;,因为我们的JVM没有办法将str1和str2自动识别成字符串,所以会将他们new 一个放置在堆内存中
  5. String str5 = new String("ab");直接创建即可
  6. String str6 = "a" + "b";我们的JVM先将"a" + “b"变成"ab”,再去赋值给str6

比较过程:

前面的不说了,重点说一下关于:System.out.println(str5.intern() == str3);


官方API:

intern

public String intern()

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

一个初始时为空的字符串池,它由类 String 私有地维护。

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

它遵循对于任何两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。

所有字面值字符串和字符串赋值常量表达式都是内部的。

返回:一个字符串,内容与此字符串相同,但它保证来自字符串池中。


上面的理解比较官方,简单来说就是,我调用了这个函数,你给我返回一个存在于常量池中的字符串,要是没有,你给我加一个

比如:str5.intern()就是调用的常量池中的ab字符串,也就是只要指向ab字符串的,就可以判定为true

System.out.println(str5.equals(str3));
    System.out.println(str5 == str3);
    System.out.println(str4 == str3);
    System.out.println(str5.intern() == str3);
    System.out.println(str5.intern() == str4);
    System.out.println(str5.intern() == str6);
    System.out.println(str3 == str6);

答案分别是:

true

false

false

true

false

true

true

2.2 final比较

看完上面的,是不是感觉自己超级牛逼,感觉啥都懂了

别慌 看这个

final String str1 = "a";
    final String str2 = "b";
    String str3 = "ab";
    String str4 = str1 + str2;
    System.out.println(str4 == str3);

按照咱们上面说的,这个不细心的可能直接就false了

细心的看到对于str1和str2被final修饰了

回想一下,final修饰变量的作用,不可变性对吧。

如果被final修饰后,JNM在使用的时候,会把他当成一个字符串来使用,也就是类似于"a" + "b"这种操作,所以,最后的值是true

3. 总结

画图---->记住intern引用---->final变量

字符串比较不过如此~简简单单


相关文章
|
3天前
|
存储 缓存 Java
滚雪球学Java(64):LinkedHashSet原理及实现解析
【6月更文挑战第18天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
11 1
滚雪球学Java(64):LinkedHashSet原理及实现解析
|
3天前
|
安全 Java 调度
Java Queue深度解析:LinkedList为何成为队列的最佳实践?
【6月更文挑战第18天】Java的`LinkedList`适合作为队列,因其双向链表结构支持O(1)的头尾操作。非线程安全的`LinkedList`在单线程环境下效率高,多线程时可通过`Collections.synchronizedList`封装。此外,它还可兼做栈和双端队列,提供任务调度的高效解决方案。
|
2天前
|
Java
JAVA多线程深度解析:线程的创建之路,你准备好了吗?
【6月更文挑战第19天】Java多线程编程提升效率,通过继承Thread或实现Runnable接口创建线程。Thread类直接继承启动简单,但限制多继承;Runnable接口实现更灵活,允许类继承其他类。示例代码展示了两种创建线程的方法。面对挑战,掌握多线程,让程序高效运行。
|
4天前
|
存储 算法 Java
Java Set深度解析:为何它能成为“无重复”的代名词?
【6月更文挑战第17天】Java Set实现无重复元素原理:HashSet利用哈希表(HashMap基础),通过hashCode()和equals()检查元素唯一性;TreeSet基于红黑树保持元素排序和唯一。选择合适的Set类(HashSet、TreeSet、LinkedHashSet)并正确实现对象的hashCode()和equals()是关键。示例代码展示了HashSet的去重功能。
|
4天前
|
Java
【Java】Object类简单解析
【Java】Object类简单解析
7 1
|
1天前
|
Java 机器人 程序员
深度解析Java正则表达式
深度解析Java正则表达式
|
1天前
|
Java 机器人 程序员
java截取字符串的几种方法
java截取字符串的几种方法
|
2天前
|
XML Java 数据格式
深度解析 Spring 源码:从 BeanDefinition 源码探索 Bean 的本质
深度解析 Spring 源码:从 BeanDefinition 源码探索 Bean 的本质
11 3
|
1天前
|
存储 NoSQL 算法
Redis(四):del/unlink 命令源码解析
Redis(四):del/unlink 命令源码解析
|
2天前
|
XML Java 数据格式
深度解析 Spring 源码:揭秘 BeanFactory 之谜
深度解析 Spring 源码:揭秘 BeanFactory 之谜
6 1

推荐镜像

更多