【java基础】String类的==和equals怎么回事?
String类是final的,代表不可以被继承了。
怎么判断一个类是不是不可变的呢?看里面的成员是不是都用final修饰过了。
String里面用byte[]存放字符串的值,而这个value也是final的。就可以认为String是一个不可变的类。String obj1=“abc”,那么你再让obj=“bcd”,那么只是让obj指向了一段新的内存区域(堆空间)。
@Stable
private final byte[] value;
类的默认equals方法(object类的)
/* == 用于引用类型,比较的是对象是否相同
equals用于比较两个对象是否相等,当对象没有override equals方法,默认的object的equals方法,比较的是对象的内存地址 */
默认的object equals方法等同于==
public boolean equals(Object obj) {
return (this == obj);
}
测试代码:
int[] arr1= new int[]{1,2,3,4};
int[] arr2= new int[]{1,2,3,4};
System.out.println("数组对象比较");
System.out.println("hash" + System.identityHashCode(arr1));
System.out.println("hash" + System.identityHashCode(arr2));
System.out.println(arr1 == arr2); // false
System.out.println(arr1.equals(arr2)); // false
System.out.println("数组比较应该用Arrays.equals" + Arrays.equals(arr1, arr2)); // true Arrays是一个java.util下的工具类
String的创建方法
1.直接创建
String s = "hello"; // "hello" 直接引用自字符串常量池
String s1 = "abc";
String s2 = "abc";
System.out.println("hash" + System.identityHashCode(s1));
System.out.println("hash" + System.identityHashCode(s2));
System.out.println(s1 == s2); // true
System.out.println(s1.equals(s2)); // true
2.new String创建
System.out.println("new String方法创建");
String s3 = new String("abc"); 常量池里创建abc(编译时),new的时候并没有用常量池里的,而是又弄了一块内存存abc。
String s4 = new String("abc");
System.out.println("hash" + System.identityHashCode(s3));
System.out.println("hash" + System.identityHashCode(s4));
System.out.println(s3 .equals( s4)); // true
System.out.println(s3 == s4); // false
3.intern创建
Returns a canonical representation for the string object.
A pool of strings, initially empty, is maintained privately by the class String.
When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.
It follows that for any two strings s and t, s. intern() == t. intern() is true if and only if s. equals(t) is true.
All literal strings and string-valued constant expressions are interned. String literals are defined in section @jls 3.10.5 of the The Java Language Specification.
Returns:
a string that has the same contents as this string, but is guaranteed to be from a pool of
System.out.println("intern方法创建");
String s5 = s3.intern(); // 看常量池中有没有abc,有的话返回常量池中的地址给s5
String s6 = s4.intern();
System.out.println("hash" + System.identityHashCode(s5));
System.out.println("hash" + System.identityHashCode(s6));
System.out.println(s5 == s6); // true
System.out.println(s5.equals(s6)); // true
字符串常量池
字符串常量池(String Pool)是在类加载的初始化阶段被初始化的。Java中的类加载过程大致可以分为以下几个步骤:
1. **加载(Loading)**:在这个阶段,类的信息被读取并转换成运行时数据结构,然后由类加载器创建一个 `Class` 对象。
2. **链接(Linking)**:链接又可以细分为验证、准备和解析三个过程:
- **验证(Verification)**:确保加载的类信息符合JVM规范,没有安全问题。
- **准备(Preparation)**:为类的静态变量分配内存,并设置默认初始值。
- **解析(Resolution)**:将类、接口、字段和方法的符号引用转换为直接引用。
3. **初始化(Initialization)**:在这个阶段,JVM开始执行类构造器 `<clinit>()` 方法,这正是字符串常量池被初始化的时机。`<clinit>()` 方法是由编译器自动收集类中的所有静态语句块和静态变量的赋值语句,并按照他们在类中出现的顺序进行合并得到的。字符串常量池的初始化就发生在这个过程中。
字符串常量池是JVM为了节省内存而使用的一种机制。当程序中的字符串字面量(如:"Hello, World!")被声明时,JVM会首先检查字符串常量池中是否已经存在一个等价的字符串。如果存在,就返回那个字符串的引用;如果不存在,就在常量池中创建一个新的字符串,并返回这个新字符串的引用。
这种机制确保了程序中所有相同的字符串字面量都只有一个存储副本,从而减少了内存的使用。
值得注意的是,字符串常量池在Java 8之前位于永久代(PermGen),但Java 8之后,字符串常量池被移动到了Java堆中。此外,字符串常量池的具体实现和行为可能会因JVM的具体实现而有所不同。
注意:String pool在java 8 以后在堆里了,不在永久代了,图上不完全正确。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述