String类以及String的周边类
目录
2.不可变特性:对象一旦创建之后,无法被任何方式修改。本身有成本的,但也有优点。优点:开发难度变得非常简单,带来很多优化空间,字符串对象可以被缓存了。
String 首先是Java 中的普通类,因此,Java中具备的特性,String对象同样具备
一、比较
String s1 = "Hello"; String s2 = "Hello";比较s1 和s2 是否相等
s1 == s2 ;【错误】用法错误,但并不意味着一定得不到正确的结果
s1.equals(s2); 【正确】
jvm保证:如果你使用正确的写法,则一定得到正确的结果。 写的正确 => 结果正确【真】;写的正确 => 结果错误【JVM 的 BUG】;写的错误 => 结果正确【真】;写的错误 => 结果错误【真】;如果你用了错误的写法,结果叫做“行为未定义”。
二、String 对象的特殊性
1.Java中有String对象,从语法上赋予了特权,双引号的使用" ... "
String s = "Hello" ,(背后蕴含着 new 对象+指向初始化的过程),不考虑优化的情况下,认为就是String s = new String("Hello");
2.Java在设计的时候,让String 对象是一种不可变的对象。String s = "Hello";//这是一个对象"Hello" s = s + "World"; //得到一个新的对象"Hello World",让s指向了这个新的对象,并不会修改老对象
3. s + "World" s += "World"
三、常用方法
1.字符串的构造
①String s = "Hello"; 最常使用
②String s = new String("Hello");
③把二进制数据(没有经过字符集解码的数据,解码成String)二进制数据的表示形式:byte[ ] bytes = {121, 131, 151},经过字符集解码,String s = new String(bytes, 0 ,bytes.length,"UTF-8"); 或者其他字符集
2.字符串的比较
equals( ... ) 相等性;equalslgnoreCase(...) 忽略大小写的相等性比较;compare To(...) 大小比较;compareTolgnoreCase(...) 忽略大小写的大小比较。
public static void main(String[] args) {
String s1 = "hello";
String s2 = "Hello";
System.out.println(s1.equals(s2)); //false
System.out.println(s1.equalsIgnoreCase(s2)); //true
System.out.println(s1.compareTo(s2)); // >0
System.out.println(s1.compareToIgnoreCase(s2)); // ==0
}
①理解字符串:字符组成的串 string(串) 一系列的字符“Hello World” 逻辑上:'H' 'e' 'l' 'l' ...
②字符串有长度(空格也算一个长度) s.length() 和数组不同,数组的length 是属性,不用加(),而s 这里是方法,需要加()调用的。粗略地认为字符的个数,不是字节的长度。 s.isEmpty() => true/false s.length() == 0等价代换
③通过字符串得到 char[ ]数组,s.toCharArray()
④取某个字符 s.charAt(index) 0 <= index < s.length(),下标错误,就会异常
3.查找类似
①从前往后找indexOf(...) 从后往前找lastindexOf(...)
String vs char找字符串还是找数组
给定 from 和不给定 from
4.数值类型、boolean 类 转字符串
String.valueOf((byte)1); String.valueOf((short)1); String.valueOf(1); String.valueOf(1L); 1.0F、1.0、' c ' 、 true 、false、null
5.大小写转换
s = t.toUpperCase() 大写 s = t.toLowerCase() 小写
Character.toUpperCase() Character.toLowerCase() // to大小写的转换
Character.isUpperCase() Character.isLowerCase() // is判断是大写还是小写
6.格式化
String s = String.format("format",args...)
四、常用方法总结
方法修饰符 | 方法名 | 参数 | 简单介绍 |
equals(...) | 另一个字符串 | 相等性比较 | |
equalsIgnoreCase(...) | 另一个字符串 | 忽略大小写的相等性比较 | |
compareTo(...) | 另一个字符串 | 大小关系比较 | |
compareToIgnoreCase(...) | 另一个字符串 | 忽略大小写的大小关系比较 | |
length(...) | 无 | 得到字符串长度 | |
charAt(...) | 下标 | 得到下标位置对应的字符 | |
toCharArray(...) | 无 | 得到字符串对应的 char 数组 | |
indexOf(...) | 待查找字符 | 从前往后找待查找字符或字符串 | |
lastIndexOf(...) | 待查找字符 | 从后往前找待查找字符或字符串 | |
contains(...) | 待查找子串 | 判断是否包含待查找子串 | |
valueOf(...) | 各种类型 | 其他类型得到字符串表示 | |
static | format(...) | 格式化和参数 | 通过格式化方式得到字符串 |
startsWith(...) | 子串 | 判断是否以子串开头 | |
endsWith(...) | 子串 | 判断是否以子串结尾 | |
replace(...) | 待替换字符,新字符 | 替换所有的待替换字符到新字符 | |
split(...) | 正则表达式的分隔符 | 按照分隔符分割字符串 | |
static | join(...) | 分隔符,字符串数组(序列) | 按照分隔符拼接字符串 |
trim(...) | 无 | 修剪字符串的开头、结尾空白字符 |
五、字符串的不可变特性及优化
1.字符串对象在编程中从来都是使用频率最高的一类对象(甚至都可以不说之一)
2.不可变特性:对象一旦创建之后,无法被任何方式修改。本身有成本的,但也有优点。优点:开发难度变得非常简单,带来很多优化空间,字符串对象可以被缓存了。
3.不可变对象大概是怎么做到的
①类不可以被继承 public final class String
②属性也往往被 final 修饰 private final char value[ ];
③防止内部的属性对象逃逸
class MyString{
private final char[] value = ... ; // final 修饰仅仅代表,value不能指向其他对象
//value[3] = 'x'仍然是可以被更改
char[] toCharArray() {return value;} 对象逃逸(字符数组对象被你返回后,脱离你的管理了)
return new char[] (value); ——给一个克隆下来的新对象
4.对象的优化
既然字符串对象使用非常频繁,有优化的必要性和紧迫性;由于字符串对象的不可变特性,留下了很大的空间用于优化。最终,JVM使用了 池化(pooled)技术来进行优化。
对象池(逻辑:使用频率比较高的字符串对象)
优化成立前提:对于对象来说,大部分情况下,不考虑对象同一性的问题,常见的都是去考虑相等性。
这个字符串对象池,命名比较混乱,常见的概念术语:StringTable、字符串表、字符串哈希表、字符串常量池
5.哪些对象会入池
①写在代码中的字面量字符串,默认入池。 " ... "引起来的都是
②new String( ... )默认不会入池
public static void main(String[] args) {
String s = "hello";
String t = "hello";
System.out.println(s.equals(t)); //true
System.out.println(s == t); //不应该做任何假设
//作为开发者就不应该比较两个字符的同一性问题
String u = new String("hello"); //默认不入池
System.out.println(s.equals(u)); //true
System.out.println(s == u); //false
}
③通过s.intern();强制 s 对象入池(逻辑上)。如果 s 所在的对象已经在池了,就返回池里的对象引用,否则,把对象搬到池了,返回引用。
结论:知道有池化优化存在即可,完全不应该去判断字符串对象的同一性问题,因为不知道是否有哪个你看不到的代码就会触发了对象的入池。只做相等性判断!!
6.StringBuilder 字符串构造器
由于字符串具备不可变特性,使得在代码中如果出现频繁拼接字符串的操作,则成本上升了
String s = "hello"; for( int i = 0;i < 1000; i++ ){ s = s + i; } 每次s = s + i,本质上都会生成一个新的字符串,让s 指向新的字符串,最终创造了大概1000 个字符串对象。
所以,我们需要一种,对象,专门来处理这种情况:StringBuilder 字符串构造器。
StringBuilder s = new StringBuilder(); 一开始是空的 new StringBuilder("hello"); 一开始就有了“hello”。 s.append(各种类型) 视为向后面做尾插操作 String s1 = s.toString(); 得到最终拼接好的字符串。 整个过程1.StringBuilder 对象 2.String 对象
7.append()方法的使用
比如有一个字符串s = "aaa",我想给s的后面拼接一些东西,这时候就可以写s.append("bbb"); 这样 s = "aaabbb"。