String三个注意事项

1、检查String是否相等

如上文提到的,检查String是否相等最好要使用equals方法,尽量少使用==操作符。

String cmower ="cmower";

System.out.println("cmower" == cmower);//true
System.out.println("cmower".equals(cmower));//true
System.out.println("cmower".substring(0, 3) == "cmo");//false
System.out.println("cmower".substring(0, 3).equals("cmo"));//true
 
  • String cmower ="cmower";
    
    System.out.println("cmower" == cmower);//true
    System.out.println("cmower".equals(cmower));//true
    System.out.println("cmower".substring(0, 3) == "cmo");//false
    System.out.println("cmower".substring(0, 3).equals("cmo"));//true

    1
  • 2
  • 3
  • 4
  • 5
  • 6
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      
      
         
      1. ==操作符确定的是两个String是否放在同一个位置上。
      2. “cmower”字符串和cmower变量指向的引用就是在同一个位置上,所以==比较结果为true。
      3. 在Java虚拟机上,只有字符串常量是共享的(”cmower”字符串和cmower变量共享了同一个地址)。但是对于substring产生的结果就不共享了。
      4. 对于equals,比较的则是两个对象是否具有相同的字符集。

      Compares this string to the specified object. The result is true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object.

      2、String不可变

      public static void main(String[] args) {
          String s = "s";
          String ss = toUpper(s);
          System.out.println(s);//s
          System.out.println(ss);//S
      }
      
      private static String toUpper(String b) {
          String bb = b.toUpperCase();
      
          System.out.println(b);//s
          return bb;
      }
          
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

      “s”是一个字符串对象,你怎么也不能把这个对象变成“S”。也就是说小s和大S尽管是双胞胎,但她们俩注定都不能成为对方。

      3、+与StringBuilder

      首先,我们先来看对于+操作符,在Java虚拟机下是如何工作的。

      public static String add1() {
          String b = "b";
          String s = "a" + b + "c" + "d" + 100;
          return s;
      }
      
      public static String add2() {
          String s = "a" + "b" + "c" + "d" + 100;
          return s;
      }
          
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10

      对于add1和add2方法,你认为Java虚拟机的工作方式一样吗?

      闭上眼睛10秒钟,先想一会。


      我们来揭晓答案: 

      差别是不是很大?

      这说明,+操作符在拼接String时,会根据情况做一定的选择。比如add1方法,Java会new 一个StringBuilder对象,来对abcd100进行append操作,之后再toString出来。

      那么也就说,Java会自动会为我们优化代码,以后我们尽管使用+操作符就行了。但事实并非如此,再来看一串代码。

      public static String plus() {
          String result = "";
          for (int i = 0; i < 10; i++) {
              result += "a";
          }
          return result;
      }
      
      public static String sb() {
          StringBuilder sb = new StringBuilder();
          for (int i = 0; i < 10; i++) {
              sb.append("a");
          }
          return sb.toString();
      }
          
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15

      这个时候,你选择用sb方法还是plus方法?

      再闭上眼睛10秒钟,想一下你的答案。


      javap执行结果如下: 

      看得出plus方法的8-34行是一个循环,11行时创建了StringBuilder对象,也就是在循环内。这个方法执行了10次,那么也就创建了10个StringBuilder对象。

      再来看sb方法的结果: 
      显而易见,StringBuilder对象只有一个。

      在使用StringBuilder时,尽量少“在append方法的参数中使用+操作符”:

      public static String sb1() {
          StringBuilder sb = new StringBuilder();
          String b = "b";
          for (int i = 0; i < 10; i++) {
              sb.append("a" + b);
          }
          return sb.toString();
      }
          
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

      这样做糟糕至极: 

      “a” + b时又重新创建了StringBuilder对象。

      总结如下, 
      1. 在进行循环多次拼接String时,用StringBuilder而不用+操作符! 
      2. +操作符只用于少量字符串变量拼接,在内存中操作,性能更高! 
      3. append方法的参数少用+操作符!

    <think>嗯,用户问的是关于String不可变性在实际编程中的应用和注意事项。首先,我需要回忆一下String不可变性的基本概念。String在Java等语言中是不可变的,也就是说一旦创建,它的值就不能被修改。这涉及到内存管理、线程安全等方面。 接下来,我应该考虑用户可能的实际应用场景。比如,字符串作为HashMap的键,因为不可变性保证了哈希值的稳定性,所以适合作为键使用。另外,多线程环境下,不可变对象是线程安全的,不需要额外的同步措施。这些都是实际应用中的优点。 然后,注意事项方面,用户可能遇到频繁拼接字符串导致性能问题的情况。比如在循环中使用+操作符拼接,会产生大量中间对象,这时候应该建议使用StringBuilder或者StringBuffer来优化。此外,字符串比较时,使用equals方法而不是==,这也是常见的注意点。 还需要考虑用户可能的误区,比如认为String不可变意味着不能修改,但实际上是通过创建新对象来实现的。所以当需要频繁修改时,选择正确的类很重要。另外,内存方面,大量相同的字符串可能会占用内存,这时候字符串池的机制和intern方法的使用可以优化内存。 用户可能是Java开发者,可能在处理字符串操作时遇到了性能问题或者线程安全问题,想了解如何正确应用String的特性。需要确保回答覆盖到应用场景、性能优化、线程安全、比较方法以及内存管理这些方面,帮助用户全面理解并避免常见错误。</think>在编程中字符串的不可变性是重要的设计特性(如Java/C#/Python等语言均采用),以下从应用场景和注意事项两个维度为您解析: 一、典型应用场景 1. 哈希键安全性 - 作为HashMap/HashTable的键时,不可变性保证hashCode()值稳定 - 示例:`Map<String, Object> config = new HashMap<>();` 2. 线程安全保证 - 无需同步即可在多线程间安全共享(如配置参数、常量值) - 示例:`public static final String API_KEY = "sk-...";` 3. 字符串池优化 - JVM通过常量池重用相同字符串,减少内存开销 - 示例:`String s1 = "hello"; String s2 = "hello"; // 指向同一对象` 4. 防御性编程 - 作为方法参数传递时不会被意外修改 - 示例:`public void process(String id) { /* id不会被改变 */ }` 二、关键注意事项 1. 拼接性能优化 - 避免循环内使用`+`拼接:`for(...){ s += str; }` → 改用StringBuilder - 大文本处理时优先选择`StringBuffer`(线程安全)或`StringBuilder` 2. 比较操作规范 - 值比较必须用`.equals()`而非`==`(`==`比较对象地址) - 示例:`"hello".equals(input)`优于`input == "hello"` 3. 内存优化技巧 - 超大字符串及时置null:`bigString = null;`(辅助GC) - 重复子串处理可用`substring()`配合intern():`subStr.intern()` 4. 敏感数据处理 - 密码等敏感信息应及时清除(因不可变特性,需用char[]代替) - 反例:`String password = "123456";` → 残留内存难以清除 三、特殊案例处理 1. 反射风险 - 通过反射可破坏不可变性(需特别注意安全场景) ```java Field valueField = String.class.getDeclaredField("value"); valueField.setAccessible(true); valueField.set(str, "hacked".toCharArray()); ``` 2. 编码转换 - 注意不同编码转换时的对象新建: ```java String s1 = new String(bytes, "UTF-8"); String s2 = new String(bytes, "ISO-8859-1"); // 产生不同对象 ``` 理解字符串不可变性的本质(修改即新建对象)是编写高效、安全代码的关键。实际开发中应根据场景合理选择StringBuilder、StringBuffer或直接操作char[]等方案。
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值