字符串,是Java中最重要的类。这句肯定的推断不是Java之父詹姆斯·高斯林说的,而是沉默王二说的,因此你不必怀疑它的准确性。

关于字符串,有很多的面试题,但我总觉得理论知识绕来绕去没多大意思。你比如说:String cmower = new String("沉默王二");定义了几个对象?

我总觉得问我这样的问题,就好像是在拷问我:“既然你家买了冰箱,你难道不应该知道冰箱制冷的原理?”

再说,为什么要用String cmower = new String("沉默王二");而不是String cmower = "沉默王二";

我劝各位面试官不要再缠住这样的问题不放了,切记“学以致用”。理论知识如果一直是在绕弯弯,那真的毫无价值。如果要我来做面试官,我想要问的问题是:“你平常是怎么判断两个字符串相等的?是用equals()还是==?”

前言就说这么多。接下来,我们来探讨几个实用的知识点。

01 字符串是不可变的

我们来看一下String类的定义:

public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {
}

可以发现,String类是final类型的,因此不能被继承。

如果类可以被继承,那么就会破坏类的不可变性机制。因为子类可以覆盖父类的方法,并且可以改变父类的成员变量值,一旦子类以父类的形式出现时,就不能保证类是不可变的。

String类的不可变性有什么好处呢?

1)作为HashMap的键。

因为字符串是不可变的,因此它在创建的时候哈希码(hash code)就计算好了。这也就意味着每次在使用一个字符串的哈希码的时候不用重新计算一次,这样更加高效,很适合作为HashMap中的键。

2)线程安全。

同一个字符串对象可以被多个线程共享,如果访问频繁的话,可以省略同步和锁等待的时间,从而提升性能。

3)字符串常量池的需要。

稍后介绍。

特别要注意的是,String类的所有方法都没有改变字符串本身的值,都是返回了一个新的对象

02 字符串常量池

在Java中,常用的创建字符串的方式有两种:

String cmower = "沉默王二";String cmowsan = new String("沉默王三");

cmower使用双引号,cmowsan使用new关键字,它们有什么区别呢?

答案如下:

String cmower = "沉默王二";
String cmower1 = "沉默王二";
System.out.println(cmower == cmower1); // 输出trueString cmowsan = new String("沉默王三");
String cmowsan1 = new String("沉默王三");
System.out.println(cmowsan == cmowsan1); // 输出false

双引号创建的相同字符串使用==判断时结果为true,而new关键字创建的相同字符串使用==判断时结果为false。

这是为什么呢?

String在Java中使用过于频繁,为了避免在系统中产生大量的String对象,Java的设计者引入了“字符串常量池”的概念

当使用双引号创建一个字符串时,首先会检查字符串常量池中是否有相同的字符串对象,如果有,则直接从常量池中取出对象引用;如果没有,则新建字符串对象,并将其放入字符串常量池中,并返回对象引用。

这也就是说,"沉默王二"是放在字符串常量池中的,cmower和cmower1两个字符串对象引用是相同的。

而new关键字创建的字符串对象是不涉及字符串常量池的,直接放在堆中,也就是说,虽然cmowsan和cmowsan1都叫沉默王三,但不一个人。

强烈建议:不要使用new关键字的形式创建字符串对象。

03 +号和StringBuilder

由于字符串是不可变的,因此字符串在进行拼接的时候会创建新的字符串对象。大家都知道,内存是一定的,因此对象创建多了就会影响系统性能。

StringBuilder正是为了解决字符串拼接产生太多中间对象的问题而提供的一个类,可以通过append()方法把字符串添加到已有序列的末尾,非常高效。

那么有人在进行字符串拼接的时候,就会产生疑惑:“我到底是用+号还是StringBuilder?”

我们先来看这样一段代码:

String chenmo = "沉默";
String wanger = "王二";
System.out.println(chenmo + wanger);

这段代码是怎么编译的呢?可以使用JAD(Java反编译工具)来看一看。

String s = "u5A0Cu5910u7CAF";
String s1 = "u941Cu5B29u7C29";
System.out.println((new StringBuilder()).append(s).append(s1).toString());

你是不是看到了StringBuilder的影子?

没错,使用+号进行字符串拼接的时候,Java编译器实际是通过StringBuilder类来完成的。

难道可以使用+号来随意拼接字符串?反正Java编译器已经自动地为我们优化了。

但事实并非如此,来看这样一段代码:

String cmowers = "";
for (int i = 0; i < 9; i++) {cmowers += "沉默王二";
}
System.out.println(cmowers);

闭上眼睛先想一想,Java编译器会怎么做?我们期望的结果是在循环外部就创建StringBuilder,Java编译器能如我们所愿吗?

JAD反编译后的结果如下:

String s = "";
for(int i = 0; i < 10; i++)s = (new StringBuilder()).append(s).append("u5A0Cu5910u7CAFu941Cu5B29u7C29").toString();System.out.println(s);

这么看来,StringBuilder是在for循环内部创建的,也就是说会创建10次。天呐,这可不是我们期望的结果!我们只希望StringBuilder创建一次。

没办法,Java编译器是做不到的,只能靠我们自己:

StringBuilder cmowers = new StringBuilder();
for (int i = 0; i < 9; i++) {cmowers.append("沉默王二");
}
System.out.println(cmowers);

强烈建议:如果只是三四个字符串的拼接,尽管使用+号操作符,别想什么性能优化(举个例子,你离目的地只有100米,你是打算打个出租车,还是自己步行走过去?);如果遇到多于四个字符串的拼接,或者需要用到循环来拼接,那就选择StringBuilder。

在我年轻的时候,我还会犯这样一个错误:

StringBuilder cmowers = new StringBuilder();
for (int i = 0; i < 9; i++) {cmowers.append("沉默王二" + "和他的读者朋友们");
}
System.out.println(cmowers);

我去,竟然在append()方法的内部使用+号!因为这个错误,我差点没被领导打死。你可要小心点。

04 关于concat()

除了使用+号和StringBuilder对字符串进行拼接,还可以使用String类的concat()方法。

concat()方法只不过是String类的一个方法而已,为什么我要单独拎出来说呢?

因为之前我要在JSP页面的EL表达式中拼接字符串,刚开始想到的是用+号操作符,但EL表达式不是Java,+号操作符是不能拼接字符串的。我当时竟然没想起来用concat()

重新铭记一下:

${item.username.concat('-').concat(item.realname)}

05 关于intern()

关于字符串的性能问题,我常在一些技术文章中看到这样的建议:“如果一个字符串使用的频率非常高,建议使用String.intern()将其缓存。”

但我并不建议你这么做,因为这个方法要显式的调用,这样很麻烦;况且,在代码编写阶段,怎么可能知道哪个字符串使用频率很高呢?

06 关于StringUtils

据我的编程经验来看,字符串的操作往往需要用到一个工具类,那就是org.apache.commons.lang3.StringUtils(null安全的,也就是说,StringUtils类的方法可以接受为null的字符串,但不会抛出NullPointerException)。

不过,我最常用的方法就那么几个:

方法等价IsEmpty(String str)`str == nullstr.length == 0`isBlank(String str)`str == nullstr.length == 0str.trim().length == 0`join(Object[] arrey)把数组中的元素连接成一个字符串返回


推荐阅读:

Java异常处理:给程序罩一层保险
Java集合类:我其实没那么简单

callablestatement.setstring会不会将字符串trim_Java String:重要到别人只能当老二的字符串类相关推荐

  1. Java String:重要到别人只能当老二的字符串类

    字符串,是Java中最重要的类.这句肯定的推断不是Java之父詹姆斯·高斯林说的,而是沉默王二说的,因此你不必怀疑它的准确性. 关于字符串,有很多的面试题,但我总觉得理论知识绕来绕去没多大意思.你比如 ...

  2. 【javascript高级教程】JavaScript 字符串(String) 对象

    String 对象用于处理已有的字符块. JavaScript 字符串 一个字符串用于存储一系列字符就像 "John Doe". 一个字符串可以使用单引号或双引号: var car ...

  3. Java字符串格式化—String.format()的使用以及Printf的使用

    Java字符串格式化-String.format()的使用以及Printf的使用 tring类的format()方法用于创建格式化的字符串以及连接多个字符串对象.记得C语言的printf()方法,两者 ...

  4. 字符串类型String总结

    1.String类: ①Java中,字符串是String类的对象: ②Java中,String是引用数据类型: ③可以通过使用String类提供的方法来完成对字符串的操作: ④创建一个字符串对象之后, ...

  5. ACMNO.27 Python的两行代码解决 C语言-字符逆序 写一函数。使输入的一个字符串按反序存放,在主函数中输入输出反序后的字符串。 输入 一行字符 输出 逆序后的字符串

    题目描述 写一函数,使输入的一个字符串按反序存放,在主函数中输入输出反序后的字符串. 输入 一行字符 输出 逆序后的字符串 样例输入 123456abcdef 样例输出 fedcba654321 来源 ...

  6. SZUACM集训字符串基础总结: 字符串最小表示 ,KMP, EXKMP, Manracher, Trie树,字符串的hash; 附带一写常见的运用技巧,邝斌大佬的板子和例题[持续更新]

    第一部分 字符串的匹配<-------->KMP 模式匹配:子串的定位运算称为串的模式匹配或串匹配. 假设有两个串S,T,设S为主串,也称正文串,T为子串,也称为模式,在主串S中查找与模式 ...

  7. R语言应用str_match函数和str_match_all函数从字符串抽取匹配的字符串模式:str_match函数抽取第一个匹配的字符串模式、str_match_all函数抽取多个匹配的字符串模式

    R语言应用str_match函数和str_match_all函数从字符串抽取匹配的字符串模式:str_match函数抽取第一个匹配的字符串模式.str_match_all函数抽取多个匹配的字符串模式s ...

  8. pandas使用pad函数向dataframe特定数据列的每个字符串添加前置(前缀)补齐字符或者字符串、向所有字符串的左侧填充、直到宽度达到指定要求(left padding)

    pandas使用pad函数向dataframe特定数据列的每个字符串添加前置(前缀)补齐字符或者字符串.向所有字符串的左侧填充.直到宽度达到指定要求(left padding) 目录

  9. 写一个函数,2 个参数,1 个字符串,1 个字节数,返回截取的字符串,要求字符串中的中文不能出现乱码

    题目要求: 写一个函数,2 个参数,1 个字符串,1 个字节数,返回截取的字符串,要求字符串中的中文不能出现乱码. 如("我ABC",4)应该截为"我AB", ...

最新文章

  1. Mp4v2封装H264+AAC为MP4
  2. 初中数学分几个模块_初中数学 8大模块,59个必考易错知识点大集合,期末考试一定要注意...
  3. 细谈Ehcache页面缓存的使用
  4. svn commit --cl app 时手动输入提交的注释,而不是在 -m 'comments here'这里输入
  5. linux下如何bash文件,Linux系统的文件管理命令及bash的相关工作特性
  6. 算法思想——贪心(详细举例理解~)
  7. java 自动装载_java_详解Java的Spring框架下bean的自动装载方式,Spring容器可以自动装配相互协 - phpStudy...
  8. 0.618 与 1.414
  9. 【.Net】win10 uwp unix timestamp 时间戳 转 DateTime
  10. 互联网光环下的新金融群像:运营最重要的是说人话
  11. 阿里云Serverless,全球第一!
  12. 获取CPU序列号的Delphi程序
  13. 自己动手,更换光猫,这次是吉比特H2-3换为华为MA5671。(中国移动光纤宽带)
  14. [MySQL]Software caused connection abort: recv failed 问题分析与解决
  15. Javascript+webdriverio App自动化demo
  16. 全球都在乘“云”而上,从十几亿暴涨至千亿规模的云计算究竟是什么来头?
  17. opencv中的split函数
  18. 丽荣葵花——从吴忠走向全国
  19. 保研边缘人如何自救(经管学姐)?
  20. 舆情监控系统python开源_TiDB 在西山居实时舆情监控系统中的应用

热门文章

  1. JAVA程序设计----集合基础之Collection
  2. Linux export 命令用法
  3. 左神算法:判断二叉树是否为平衡二叉树(树形dp套路,Java版)
  4. Python解释器和IPython
  5. lazada发货_Lazada怎么发货?最全Lazada发货流程及注意事项!值得收藏!
  6. Megastore:为交互式服务提供可扩展的高可用性存储
  7. Go 语言学习笔记(三):类型系统
  8. vmstat使用简介各种linux命令使用
  9. 1081 Rational Sum (20 分)_22行代码AC
  10. PostProcessor