透析Java本质的36个话题03String类

发布时间 2023-11-26 22:32:17作者: lartimes

1.来龙去脉- “+” 是怎么连接字符串的?

“+” 号对String对象的连接

Oracle JDK1.7的实现: 
	当使用+ 字符串拼接,会创建一个临时的StringBuilder对象,该对象调用append连接操作。
	类似于 StringBuilder.append(s1).append(s2).toString;

"+" 的性能

  • 如果是在循环中对String对象进行连接,应该直接使用StringBuilder代替String的"+" , 这样子可以提供1性能
  • 当使用运算符“+”来连接字符串时,实际上是使用临时创建的StringBuilder对象来辅助完成的。不同的编译器在处理上也略有不同。
  • 对于编译时常量,在编译后直接计算出字符串的值,而不会在运行时创建临时的StringBuilder对象来完成字符串连接。

2.一成不变-不可修改的String对象

​ 设计为不可变最大好处就是可以实现资源共享。在多线程操作的时候,可以将其认为是不可变得,而不用担心其他线程会对其进行修改操作。
这样,访问String对象的时候,就没有必要使用线程同步操作

String类是非可变类,其对象一旦创建,就不可修改。
String类那些看似修改字符序列的方法实际上都是返回新创建的String对象,而不是修改自身对象。
·由于 String对象是不可改变的,因此其具有线程安全性,可以自由地实现共享。

3.钩深索隐-String字符最大长度的探索

        String a = "werege";
        int length = a.length();
        char[] chars = new char[Integer.MAX_VALUE>>2];
//        Exception in thread "main" java.lang.OutOfMemoryError: Requested array size exceeds VM limit
//        char : 2Byte, 超出String默认最大长度限制了
  • String内部,使用一个字符数组(char[]) 来维护字符序列的
  • String的最大长度也就是字符数组的最大啊啊长度,理论上最大长度为int类型2147483647。
  • 由于计算机当前可用内存大小、分配诸多原因。可申请的最大值也是一个近似值1,不完全准确。 java 0Xmx1G className

Java中的对象是分配在堆上 ,堆的大小直接决定我们所能创建对象的多少。堆空间默认最大值256MB

4.追本溯源-追寻String字面常量的“极限”

  • String字面常量与String长度的区别。
  • CONSTANT Utf8info表结构。
  • 各区间字符在CONSTANT_Utf8_ info表中的存储。
  • 最大字面常量长度。
String字面常量的最大长度与String在内存中的最大长度是不一样的,后者的最大长度为int类型的最大值,即 2147483647,而前者根据字符(字符Unicode值)的不同,最大长度也不同,最大长度为65534(可手动修改class文件,令输出结果为65535)。
String字面常量的最大长度是由 CONSTANT_Utf8_info表来决定的,该长度在编译时确定,如果超过了CONSTANT_Utf8_info表 bytes数组所能表示的上限,就会产生编译错误

5.话题21旧调重弹——再论equals 方法与“-=”区别

​ 这一块太枯燥了 都是基础。。

  • equals方法比较的标准。
  • equals方法与“==”的真正区别。
  • 重写equals方法需要遵守的规则。
  • 重写hashCode方法需要遵守的规则。
  • 违背equals或 hashCode方法规则的后果。

equals重写规则

1.自反性
2.对称性
3.传递性
4.一致性
5.杜宇任何非空引用x , x.equals(null) 应该返回falsee

当进行子类继承,并且新增成员属性,重写equals方法啊, 不再具有传递性(子类与子类不能进行混合想等比较)

String intern方法

​ 当需要将莫格儿String镀锡甲肮如常量池中,就可以调用intern方法啊来完成,这个操作也称作拘留字符串。前面提到,系统会自动将String字面常量与String常量边爱澳大使的字符串值加入常量池中,这也是通过调用intern方法啊来实现的。

String a = "aaa";
String b = new String("aaa");
boolean flag = a.intern().equals(b.intern());
System.out.println(flag);
	String类维护一块特殊的区域,称为常量池。因为String对象是不可改变的,因此没有必要创建两个相同的 String对象。只需将String对象加入常量池,在需要的时候取出,这样即可实现String对象的共享。
	在程序中出现String编译时常量(String 字面常量与String常量表达式)时,会自动调用intern方法,如果常量池中含有相等的String对象,则直接返回常量池中的对象,否则将对象加入常量池中并返回该对象。
	对于运行时创建的String对象(非 String编译时常量),会分配到堆中,系统不会自动调用intern方法拘留对象,不过我们依然可以自行嗲用该对象的intern方法对该对象进行拘留