推荐使用String直接赋值

String 的生成方式:

  • 通过 new 关键字进行创建:String str = new String(“中国”);
  • 通过String字面量直接赋值:String str = “中国”;

两种生成方式的区别:

  1. String str1 = "中国";
  2. String str2 = "中国";
  3. String str3 = new String("中国");
  4. String str4 = str3.intern();
  5. // == 判断的是两个对象的引用地址是否相同
  6. System.out.println(str1 == str2); // true
  7. System.out.println(str1 == str3); // false
  8. System.out.println(str1 == str4); // true

解释:

  • java 为了避免在一个系统中大量产生 String 对象(String 在程序设计中属于最常使用的类型),就设计了一个字符串常量池(String Pool),在字符串常量池中所容纳的都是 String 字符串对象。
  • 字符串常量池中对象的创建机制:使用字符串字面量创建一个字符串(即 String str = “中国”; )时,先检查池中是否有字面量值相等的字符串
    • 如果有,则不再创建,直接返回池中该对象的引用
    • 如果没有,则先创建该字符串对象,然后将该对象放到池中,再返回引用
  • 通过 new String() 创建一个 String 对象是不检查字符串池,也不会将该对象放到池中
  • String.intern() 方法会检查当前对象在对象池中是否存在有字面量值相同的引用对象
    • 如果有,则返回池中对象
    • 如果没有则会先创建此对象,然后将创建的对象放置到常量池中,并返回常量池中的对象
  • 字符串进行运算时,如果表达式中存在变量(如 String a = “Hello”; String b = a + “ World” ;),则该 b 对象不会进入字符串常量池

测试 String.intern() 方法:

  • 先使用 new String() 创建一个不会进入常量池的 String 对象
  • 然后再使用 String.intern() 方法将该对象放入常量池
  • 再使用相同字面量创建 String 对象 ```java String str1 = new String(“中国”); String str2 = str1.intern(); String str3 = “中国”;

System.out.println(str1 == str2); // false System.out.println(str1 == str3); // false System.out.println(str2 == str3); // true

  1. 字符串常量池不会产生线程安全问题:String 是一个不可变对象(Immutable),该不可变有两层意思
  2. - String 是一个 final 类,不可以被继承,不能产生一个 String 的子类
  3. - String 提供的所有方法中,如果有 String 返回值,都会新建一个 String 对象,不对原对象进行修改,这就保证了原对象是不可改变的
  4. 字符串常量池不需要考虑垃圾回收:虽然 java 的每个对象都保存在堆内存中,但是字符串常量池非常特殊,在编译器就已经决定其存在于 JVM 的常量池(Constant Pool),垃圾回收器不会对其进行回收。
  5. <a name="aCHVz"></a>
  6. #### replace和replaceAll
  7. 常用的字符串替换函数:String.replace() String.replaceAll()
  8. String.replace(String oldChar, String newChar):将指定目标字符串中的指定字符(串)**全部**替换成新的字符(串)
  9. - oldChar:被替换的字符串
  10. - newChar:用于替换的字符串
  11. String.replaceAll(String regex, String replacement):将目标字符串中匹配某正则表达式的**所有子字符串**替换成新的字符串
  12. - regex:正则表达式
  13. - replacement:用于替换的字符串
  14. String.replaceFirst(String regex, String replacement):将目标字符串中匹配某正则表达式的**第一个子字符串**替换成新的字符串<br />注意:
  15. - \ java在属于转义字符,因此需要用两个 \\ 来表示一个 \
  16. - \ 在正则表达式中也是转义字符,也需要用两个 \\ 代表一个
  17. ```java
  18. String str = "////世界";
  19. System.out.println(str.replace("/","\\")); // 结果:\\\\世界
  20. System.out.println(str.replaceAll("/","\\\\")); // 结果:\\\\世界

String、StringBuilder、StringBuffer

  • String 类:不可变的常量,String 的所有方法都会返回一个新的 String 对象,用于字符串不经常变化的场景
  • StringBuilder:非多线程安全的可变字符序列,在内存中保存的是一个有序的字符序列(char类型的数组),用于单线程中频繁进行字符串运算的场景,如 SQL 语句的拼装等
  • StringBuffer:相当于在 StringBuilder 的相关方法上加了 synchronized 关键字,线程安全的可变字符序列,用于多线程中频繁进行字符串运算的场景,如 HTTP 参数解析等

加号的连接机制

在 java 中对于加号 + 的处理机制:在使用加号进行计算的表达式中,只要遇到 String ,则所有的数据都会转换成 String 类型进行拼接;如果是原始数据,则直接拼接,如果是对象,则调用 toString 方法的返回值进行拼接

  1. String str = "Hello";
  2. Integer i = 18;
  3. int j = 9;
  4. List<Integer> integers = Arrays.asList(1, 2, 3);
  5. // 报错,Operator '+' cannot be applied to 'int', 'java.util.List<java.lang.Integer>'
  6. System.out.print ln(i + j + integers + str);
  7. // 27Hello[1, 2, 3]
  8. System.out.println(i + j + str + integers);
  9. // Hello189[1, 2, 3]
  10. System.out.println(str + i + j + integers);

在 + 表达式中,String 字符串具有最高的优先级,java 的执行顺序是从左到右,因此 i + j + str + integers ,在执行到 str 时,其后所有的计算都会变成字符串,因此 integers 对象就会自动调用它的 toString() 方法,然后进行拼接。

字符串拼接

对一个字符串进行拼接有三种方法:拼接效率依次降低

  • 加号
  • contact
  • StringBuilder 的 append 方法
  1. // 1.加号 + 拼接字符串:在编译器中会使用StringBuilder.append()方法进行追加
  2. // 等效于 str = new StringBuilder(str).append("c").toString();
  3. str += "c";
  4. // 2.concat方法拼接:底层是数组拷贝
  5. str.concat("c");
  6. // 3.StringBuilder.append()
  7. builder.append(str).append("c").toString();

建议使用UTF-8编码

Java 程序设计到编码的部分:

  1. java 文件编码:
    • 使用记事本创建一个 .java 后缀的文件,则文件编码为操作系统默认的编码格式
    • 使用ide工具创建,则依赖于ide的设置,一般ide默认的是操作系统编码(Windows一般为 GBK)
  2. Class 文件编码:在任何操作系统上,通过 javac 命令生成的后缀名为 .class 的文件都是UTF-8 编码的 UNICODE 文件,在编译时显示指定 .java 文件的编码格式:javac -encoding CBK xx.java

中文排序

  1. // 中文字符排序
  2. String[] str = {"张三(Z)", "李四(L)", "王五(W)"};
  3. // 排序,默认升序
  4. Arrays.sort(str);
  5. for (String s : str) {
  6. // 张三(Z) 李四(L) 王五(W)
  7. System.out.print(s + "\t");
  8. }

很明显,排序结果不是我们想要的,Arrays 工具类默认排序是通过数组元素的 compareTo 方法进行比较的,而 String 类的 compareTo 方法的比较源码如下:

  1. while (k < lim) {
  2. // 原字符串的字符数组
  3. char c1 = v1[k];
  4. // 比较字符串的字符数组
  5. char c2 = v2[k];
  6. if (c1 != c2) {
  7. // 比较两者的 char 值大小
  8. return c1 - c2;
  9. }
  10. k++;
  11. }

即先取得字符串的字符数组,然后逐一比较(字符),也就是比较 unicode 的码值,因此比较结果会不符合预期。
在 java 中,提供了 Collator 类用于进行非英文字符的排序:

  1. // java建议使用Collator对非英文进行排序
  2. // 定义一个中文排序器
  3. Comparator<Object> instance = Collator.getInstance(Locale.CHINA);
  4. // 升序排列
  5. Arrays.sort(str, instance);
  6. for (String s : str) {
  7. // 李四(L) 王五(W) 张三(Z)
  8. System.out.print(s + "\t");
  9. }