Java String:重要到别人只能当老二的字符串类
字符串,是Java中最重要的类。这句肯定的推断不是Java之父詹姆斯·高斯林说的,而是沉默王二说的,因此你不必怀疑它的准确性。
关于字符串,有很多的面试题,但我总觉得理论知识绕来绕去没多大意思。你比如说:String cmower = new String("沉默王二");
定义了几个对象?
我总觉得问我这样的问题,就好像是在拷问我:“既然你家买了冰箱,你难道不应该知道冰箱制冷的原理?”
再说,为什么要用String cmower = new String("沉默王二");
而不是String cmower = "沉默王二";
?
我劝各位面试官不要再缠住这样的问题不放了,切记“学以致用”。理论知识如果一直是在绕弯弯,那真的毫无价值。如果要我来做面试官,我想要问的问题是:“你平常是怎么判断两个字符串相等的?是用equals()还是==?”
前言就说这么多。接下来,我们来探讨几个实用的知识点。
01 字符串是不可变的
我们来看一下String类的定义:
public final class String implements 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); // 输出true
String 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 = "\u5A0C\u5910\u7CAF";String s1 = "\u941C\u5B29\u7C29";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("\u5A0C\u5910\u7CAF\u941C\u5B29\u7C29").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 == null || str.length == 0
|
isBlank(String str)
|
str == null || str.length == 0 || str.trim().length == 0
|
join(Object[] arrey)
|
把数组中的元素连接成一个字符串返回 |
推荐阅读:
Java异常处理:给程序罩一层保险
Java集合类:我其实没那么简单
转载于:https://www.cnblogs.com/qing-gee/p/10277688.html
Java String:重要到别人只能当老二的字符串类相关推荐
- callablestatement.setstring会不会将字符串trim_Java String:重要到别人只能当老二的字符串类
字符串,是Java中最重要的类.这句肯定的推断不是Java之父詹姆斯·高斯林说的,而是沉默王二说的,因此你不必怀疑它的准确性. 关于字符串,有很多的面试题,但我总觉得理论知识绕来绕去没多大意思.你比如 ...
- Java String trim()方法示例
Java String trim() method is used to remove leading and trailing whitespaces from a string. This met ...
- Java - String源码解析及常见面试问题
文章目录 Pre Q1: String 是如何实现的? Q2: String 有哪些重要的方法? 构造函数 equals() compareTo() [equals() vs compareTo() ...
- java String长度与varchar长度匹配理解(字符和字节长度理解)
java String长度与varchar长度匹配理解(字符和字节长度理解) string中的length()长度,返回的是char的数量,每个char可以存储世界上任何类型的文字和字符,一个char ...
- java const string_深入研究Java String
开始写 Java 一年来,一直都是遇到什么问题再去解决,还没有主动的深入的去学习过 Java 语言的特性和深入阅读 JDK 的源码.既然决定今后靠 Java 吃饭,还是得花些心思在上面,放弃一些打游戏 ...
- java string逆序_java经典入门算法题,java初学者必备
java经典入门算法题 开头求关注警告 喜欢这样文章的可以关注我,我会持续更新,你们的关注是我更新的动力!需要更多java学习资 料的也可以私信我! 祝关注我的人都:身体健康,财源广进,福如东海,寿比 ...
- java string 栈_Java堆和栈的区别(String类)
堆与栈 Java的堆是一个运行时数据区,对象从中分配空间.这些对象通过new.newarray.anewarray和multianewarray等指令建立,它们不需要程序代码来显式地释放.堆是由垃圾回 ...
- Java String源码解析
String类概要 所有的字符串字面量都属于String类,String对象创建后不可改变,因此可以缓存共享,StringBuilder,StringBuffer是可变的实现 String类提供了操作 ...
- Java String 探索
今天看到了一个Java string的相关问题,解决问题的过程中就想把string 好好理顺了,总结在这里. == 和 equals() == 是判断两个变量是否指向同一个对象,equals()只判断 ...
最新文章
- leetcode - Populating Next Right Pointers in Each Node II
- IMX6ULL的GPIO操作方法
- java基础系列:集合基础(1)
- 《流畅的python》学习日志----装饰器工厂函数
- Linq表达式、Lambda表达式你更喜欢哪个?
- 【渝粤教育】国家开放大学2019年春季 2773特种动物养殖 参考试题
- 进程控制3--signal
- 字符串转内存c语言,【一起学C】C语言面试题必考:字符串操作函数,内存操作函数实现...
- excel文件修复工具_win10上使用SFC工具修复损坏的系统文件,安全高效,维修电脑必会...
- python编程入门书籍-零基础学习Python编程,这8本书必看!
- C语言输出AB9798,c语言基础练习习题及答案.doc
- delphi代码在linux编译运行,[教程] Delphi 10.2 Linux 程序开发环境部署的基本步骤
- 最新版ins安装包下载
- SCI收录中国期刊国家一级期刊名录一览表
- Python基础:68 个 Python 内置函数详解
- Tomcat无法启动,报错java.lang.NoClassDefFoundError: or...
- Qt 之数据库QSqlite应用
- 【Hash篇】HashTab一款可扩展资源管理器的哈希校验软件
- 戴尔台式机修复计算机,dell电脑win10自动修复你的电脑未正确启动怎么修复
- c 语言 蒙特卡洛程序,蒙特卡洛步骤学习(一)
热门文章
- Microwindows及基于Nano-X的简单程序开发
- RTL 和 综合 等一些基本概念的摘记
- PHP-ExcelReader
- 云计算与 OpenStack - 每天5分钟玩转 OpenStack(14)
- 《心欢喜,灵快乐》出版
- VS2015 + CUDA 8.0 配置GTX1070的OpenCL 开发环境
- java程序设计与实践教程 王薇 doc_Java程序设计与实践教程 王薇主编 答案
- api有哪些 javasocket_socket及socket java api
- appimage文件怎么安装_bauh:在一个界面中管理 Snap、Flatpak 和 AppImage | Linux 中国...
- php导出excel出现乱码,php导出数据到excel出现乱码的解决办法