这是蜗牛互联网的第 113 期原创。
作者 | 红色蜗牛
起源 | 蜗牛互联网(ID: woniu_internet)
转载请分割受权(微信 ID: 919201148)
本文纲要:
前言
在上一篇文章 Java 根本类型的各种运算,你真的理解了么?里,咱们学习了 Java 的根本类型和他们之间的运算。Java 根本类型堪称是 Java 世界里应用最频繁的数据类型了。除此之外,有种数据类型你也肯定会遇到,它在 Java 世界里应用也相当频繁。它就是字符串!
听到字符串,你是不是想起了字符这种类型。不过在 Java 里,字符和字符串是两种不同的类型。
字符串的定义与模式
字符类型你应该比拟相熟,通过关键词 char 来申明一个字符。
值只能是 一个英文字符 或者 一个中文字符 或者是 Unicode 编码 ,用 单引号 包住。如下:
`// char 用 ascii 字符赋值 `
`char charWithAscii = '.';`
`char charWithZh = '牛';`
`char a = '\u0041';// 值为 A`
而字符串,顾名思义,就是多个字符连贯而成的串。通过关键词 String
来申明一个字符串。
值能够是 null 或者 空字符串 或者 单字符串 或者 多字符串 ,用 双引号 包住。如下:
`// null 字符串,未指定地址 `
`String nullStr = null;`
`// 空字符串,蕴含 0 个字符 `
`String blankStr = "";`
`// 蕴含一个字符 `
`String oneCharStr = "A";`
`// 蕴含多个字符,打印 蜗牛 666 A`
`String multiCharStr = "蜗牛 666 \u0041";`
你会发现字符串的值能够是 null,因为字符串类型 String 是援用类型,值为 null,就阐明值不存在,也就是这个变量不指向任何对象。这也是它和根本类型 char
的区别所在。
那作为援用类型,String 就能够通过 new
的形式申明,比方:
`String newStr = new String("蜗牛 666");`
另外,你也会发现字符串比字符存储了更丰盛的数据,实际上,一个字符串能够存储 0 到任意多个字符。只有把数据内容用双引号包起来就好。
不过,如果你的数据内容自身就有双引号,会产生什么呢?
没错,连编译都过不去!编译器会提醒你字符串非法行尾,因为编译器判断的时候,会把两头引号当成字符串结尾,导致第三个引号开始的字符串语法出错。
那此时就要用到转义字符了,这个 case 里能够通过反斜杠 \
本义两头的引号。
`String str = "蜗牛 666\"";`
这样就不会报错了。
字符串的存储形式
咱们晓得,程序在运行时,会针对不同类型的变量数据做运算,最终输入后果。那其实运算过程中的变量数据都是存在栈里边,依据栈先进后出的特点,实现程序的运行逻辑。而对 Java 这种面向对象编程的语言,对象的信息就没放栈里边,而存到了堆里边,栈只存对象的援用地址。
另外,有些数据要求是不可变的,Java 会调配一块常量池进去。
比方 String 的场景。
`String str1 = "蜗牛 666";`
`String str2 = "蜗牛 666";`
`String newStr1 = new String("蜗牛 666");`
`String newStr2 = new String("蜗牛 666");`
str1 和 str2 就存储在常量池中。而常量池中的数据只有一份,因而 str1 和 str2 其实是指向同一块内存空间。
newStr1 和 newStr2 是通过 new
语法创立的对象,在创立的过程中,Java 会先去常量池中查找是否已有 蜗牛 666 对象,如果没有则在常量池中创立一个 蜗牛 666 对象,而后在堆中创立一个 蜗牛 666 的拷贝对象。
所以 new String("xxx");
这行代码会产生几个对象?
答案是一个或两个。如果常量池中原来没有 xxx,就是两个。如果有就是一个。
字符串的特点
字符串最大的特点就是 不可变性。前边也有提过,字符串在常量池会有一份,常量这个信息就阐明字符串具备不可变性了。
咱们看下实例,你猜下以下程序会输入什么:
`String strChange = "蜗牛 666";`
`System.out.println(strChange);`
`strChange = "蜗牛 888";`
`System.out.println(strChange);`
都是 蜗牛 666?因为字符串不可变嘛
事实上不是:
` 蜗牛 666`
` 蜗牛 888`
难道 蜗牛 666 被改成 蜗牛 888 了?
实际上不是,蜗牛 666 和 蜗牛 888 都在,只是 strChange 的指向变了。
程序在执行 String strChange = "蜗牛 666";
时,JVM 虚拟机先在常量池创立字符串 蜗牛 666
,而后把变量 strChange
指向它。
而后在执行 strChange = "蜗牛 888";
时,JVM 虚拟机先在常量池创立字符串 蜗牛 888
,而后把变量 strChange
指向它。
所以你会发现,刚开始的字符串 蜗牛 666
还在,只是变量 strChange
不再指向它了。
因而,字符串的不可变个性,是指 字符串内容不可变。
另外,字符串的不可变个性,也带来了两个益处。
一个是 String 对象能够缓存哈希码。在 String
类的源码中,你能够看到这么一个属性。
`/** Cache the hash code for the string */`
`private int hash; // Default to 0`
hash
的值是基于字符串的每个字符计算得出。那字符串的不可变个性,就能保障 hash
的唯一性,因而能够缓存起来,被频繁应用。这也是性能优化的一种伎俩。
另外一个就是字符串的不可变个性保障了很多场景下的平安。
很多 Java 类库都会抉择 String 作为参数,像文件门路 path 这些。如果 String 会常常扭转,那就有各种安全隐患。
字符串的罕用场景
比拟
和根本类型相比,字符串也有比拟的能力。比方上面的比拟形式。
`String equalChar = "蜗牛";`
`String euqalCharCompare = "蜗牛";`
`System.out.println(equalChar == euqalCharCompare);`
间接常量定义的形式,没有问题,会输入 true
。但如果通过 new
的形式定义那就容易出错了,比方以下的代码,你晓得输入什么么?
`String equalMethod = new String("蜗牛");`
`String euqalMethodCompare = new String("蜗牛");`
`System.out.println(equalMethod == euqalMethodCompare);`
会输入 false
,而这是不合乎咱们预期的。为什么会这样呢?
因为 ==
对于援用类型而言,比拟的是援用的地址。而上边两个字符串都是 new
进去的新对象。援用地址天然不同。
那如果想只比拟内容怎么做呢?能够应用 Java String 自带的 equals
办法!
`System.out.println(equalMethod.equals(euqalMethodCompare));`
此时就能失常输入 true
了。
拼接
最简略的拼接就是用 +
连接符,比方以下代码。
`/**`
`* 字符串连贯 `
`*`
`* @author 蜗牛 `
`* @from 公众号:蜗牛互联网 `
`*/`
`public class StringConnect {`
`public static void main(String[] args) {`
`String name = "蜗牛";`
`String age = "18";`
`String profile = name + " " + age;`
`System.out.println(profile);`
`}`
`}`
运行代码会输入:
` 蜗牛 18`
咱们能够通过反编译看下,这段代码产生了什么,输出命令:
`javap -c StringConnect`
咱们看到有如下输入:
你会发现,加号连接符实际上是 Java 编译器的优化,底层是用了 StringBuilder
这个类,它的 append
办法就起了拼接的成果。
如果拼接的字符串数量无限,绝对固定,倡议用加号连接符,这样一行代码搞定!
如果拼接的字符串有相干的逻辑,比方循环拼接,字符串数量不太固定,那倡议用 StringBuilder
这个工具类。
另外,StringBuilder
是线程不平安的,如果你是多线程开发环境,为了保障程序不出错,能够用它的兄弟类 StringBuffer
,这个类办法和 StringBuilder
统一,只是减少了线程平安的能力。
总结
本文围绕着字符串介绍了它的定义和模式,另外它的存储形式如果理解不清晰的话,在一些逻辑判断上容易出错。字符串的不可变个性,既晋升了它的拜访性能,又保障了安全性。字符串最罕用的场景,就是比拟和拼接,当然还有很多其余应用场景,咱们后边能够再细讲。
我是蜗牛,大厂程序员,专一技术原创和个人成长,正在互联网上摸爬滚打。欢送关注 我,和蜗牛一起成长,咱们一起牛~ 下期见!