一.创建字符串
常见构造String类的方式
//方式1.
String s1 = "Hello word";
//方式2.
String s2 = new String("Hello word");
//方式3.
char[] array = {'a','b','c'};
String s3 = new String(array);
注意:
- “hello”这样的字符串字面值常量,类型也是String
- String是引用类型
String 在底层的 存储方式:
二.比较字符串相等
如果说两个 int 比较大小:
int a = 10;
int b = 10;
System.out.println(a == b);
//true
但是两个 String 比较大小:
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2);
//true
看起来没什么问题,但是 :
String s3 = new String("hello");
String s4 = new String("hello");
System.out.println(s3 == s4);
//false
来看一下 两个代码的 内存布局:
s1
和 s2
都指向的是 常量池中的hello
,指向的是同一个对象
然而 s3
和s4
都是 new
出来的String
对象 所有存放在堆中 分别指向的是不同的对象
String使用==比较的是两个引用是否指向同一个对象,而不是字符串的内容
如果想比较字符串内容 可以使用equals()方法
String s5 = new String("hello");
String s6 = new String("hello");
System.out.println(s5.equals(s6));
//true
三.字符串常量池
在JVM
底层实际上维护了一个字符串常量池:
- 如果采用直接赋值的模式给
String
类的对象实例化操作,那么这个字符串内容将会自动保存在这个常量池中 - 如果下次继续使用直接赋值的模式声明
String
类,如果常量池中有,将直接进行引用 - 如果没有,则开辟新的字符串对象而保存在常量池中,以便于下次使用
我们可以使用
String
的intern
方法手动把String
对象加入到字符串常量池中
解释String类两种对象实例化的区别
1.直接赋值:只会开辟一段堆内存空间,并且该字符串对象可以自动保存在字符串常量池中,以供下次使用
2.构造方法:会开辟两块堆内存空间,其中一块成为垃圾空间,不会自动保存在对象池中,可以使用intern
方法手工入池
我们一般使用直接赋值的方式创建String对象
四.理解字符串不可变
String类的内部实现也是基于char[]
来实现的,但是String
类并没有提供set
方法之类的来修改内部的字符数组
比如:
String s1 = "hello";
s1 = s1 + "word";
s1 += "!!!";
System.out.println(s1);
//执行结果
hello word !!!
+=
看起来像是修改了字符串 其实不是,内存变化如下:
+=
之后s1
打印的结果变了,但是 不是 String
对象本身发生变化,而是s1
引用了其他的对象
如果需要改字符串,那就需要借助原字符串,创建新的字符串
String str = "Hello";
str = "h" + str.substring(1);
System.out.println(str);
//运行结果
hello
为什么String要不可变?(不可变的好处是什么)
1.方便实现字符串常量池,如果String
可变,那么常量池就要考虑何时深拷贝字符串的问题
2.不可变对象是线程安全的
3.不可变对象更方便缓存hash code
,作为 key
时可以更高效的保存到HashMap
中
五.字符、字节与字符串
5.1 字符与字符串
将字符数组中的所有内容变为字符串
public String (char[] value)
将部分字符数组中的内容变为字符串
public String (char[] value,int offset,int count)
取得指定索引位置的字符,索引从0开始
public char charAt(int index)
将字符串变为字符数组返回
public char[] toCharArray()
5.2 字节与字符串
将字节数组变为字符串
public String (byte[] bytes)
将部分字节数组中的内容变为字符串
public String (byte[] bytes,int offset,int length)
将字符串以字节数组的形式返回
public byte[] getBytes()
编码转换处理
public byte[] getBytes(String charsetName) throws UnsupportedEncodingException
六.字符串常见操作
6.1 字符串比较
区分大小写的比较
public boolean equals(Object anObject)
不区分大小写的比较
public boolean equalsIgnoreCase(String anotherString)
比较两个字符串大小的关系
public int compareTo(String anotherString)
如果两个字符串相等 返回0
如果小于 返回小于0的数
如果大于 返回大于0的数
compareTo() 是一个可以区分大小写关系的方法:
字符串比较大小的规则 ,相当于判定两个字符串在一本词典的前面还是后面 ,先根据unicode的值比较第一个字符的大小,如果不分胜负,就依次比较后面的内容
6.2 字符串的查找
判断一个子字符是否存在
public boolean contains(CharSequence s)
从开始查找指定字符串的位置,查到了返回位置的开始索引,没查到返回-1
public int indexOf(String str)
从指定位置开始查找子字符串的位置
public int indexOf(String str,int fromIndex)
从后向前查找子字符串的位置
public int lastIndexOf(String str)
从指定位置从后向前查找
public int lastIndexOf(String str,int fromIndex)
判断是否以指定字符串开头
public boolean startsWith(String prefix)
从指定位置开始判断是否以指定字符串开头
public boolean startsWith(String prefix,int toffset )
判断是否以指定字符串结尾
public boolean endsWith(String suffix)
6.3 字符串替换
替换所有的指定内容
public String replaceAll(String regex,String replacement)
替换首个内容
public String replaceFirst(String regex,String replacement)
6.4 字符串拆分
将字符串全部拆分
public String[] split(String regex)
将字符串部分拆分,该数组长度就是limit极限
public String[] split(String regex,int limit)
- 做字符串拆分时,一定要注意有些特殊字符作为分隔符可能无法正确拆分,需要加上转义
- 字符"|","*","+“都要加上转义字符,前面加上”"
- 而如果是"",那么就要写成"\"
- 如果一个字符串中有多个分隔符,可以用"|"作为连字符
6.5 字符串截取
从指定索引截取到结尾
public String substring(int beginIndex)
截取部分内容
public String substring(int beginIndex,int endIndex)
- 截取部分内容,区间是前闭后开
6.6 其他操作方法
去掉字符串中的左右空格,保留中间空格
public String trim()
字符串转大写
public String toUpperCase()
字符串转小写
public String toLowerCase()
字符串入池操作
public native String intern()
字符串连接,等同于+,不入池
public String concat(String str)
取得字符串长度
public int length()
判断是否为空字符串,不是null,而是长度为0
public boolean isEmpty()
七. StringBuffer和StringBuilder
String
和Stringbuffer
最大的区别就在于String
的内容无法修改,而StringBuffer
的内容可以修改
String
中用+连接字符串 而StringBuffer
中需要更改为append()
方法
注意 :String
和StringBuffer
不能直接转化.如果需要转换 可以采用
String
变为StringBuffer
:利用StringBuffer
的构造方法或者append()
方法StringBuffer
变为String:
调用toString()
方法
StringBuffer
还有一些方法:
1.字符串反转:
public synchronized StringBuffer reverse()
2.删除指定位置的数据
public synchronized StringBuffer delect(int start,int end)
3.插入数据
public synchronized StringBuffer insert(int offset,各种数据类型 b)
String、StringBuffer、StringBuilder的区别:
- String的内容不可修改,Stringbuffer和StringBuilder的内容都可以修改
- StringBuffer、StringBuilder大部分功能是相似的
- StringBuffer采用同步处理,属于线程安全操作,而Stringbuilder采用异步处理,属于线程不安全操作