文章目录
String类的概述
-
String类:代表字符串,Java程序中所有字符串字面量都作为此类的实例实现
-
String是一个final类,代表不可变的字符序列
-
字符串是常量,用双引号引起来表示。它们的值在创建后不可修改
-
String对象的字符内容是存储在一个字符数组value[]中的
-
源码:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0
理解String的不可变性
public class StringTest {
/*
String:字符串,使用一对""进行表示
1.String声明为final,不可被继承
2.String实现了Serializable接口:表示字符串是支持序列化的
3.String实现了Comparable接口:表示String可以比较大小
4.String内部定义了final char[] value用来存储字符串数据
5.String代表一个不可变的字符序列。简称:不可变性。
体现1:当对字符串重新赋值时,需要重新指定内存区域赋值,不能使用原有的value进行赋值
体现2:当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值
体现3:当调用String的replace()方法修改字符或字符串时,也必须重新指定内存区域赋值
6.通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中
7.字符串常量池中是不会存储相同内容的字符串的
*/
@Test
public void test1(){
String s1 = "abc"; //字面量的定义方式
String s2 = "abc";
System.out.println(s1==s2);
s1 = "hello";
System.out.println(s1); //hello
System.out.println(s2); //abc
System.out.println("-------------");
String s3 = "abc";
s3 += "def";
System.out.println(s3);//abcdef
System.out.println("-------------");
String s4 = "abc";
String s5 = s4.replace('a','m');
System.out.println(s4);
System.out.println(s5);
}
}
String不同实例化方式的对比
public class StringTest {
/*
String的实例化方式
方式一:字面量定义的方式
方式二:通过new+构造器的方式
*/
@Test
public void test1(){
//字面量定义方式,此时s1和s2的数据javaEE声明在方法区中的字符串常量池中
String s1 = "javaEE";
String s2 = "javaEE";
//通过new+构造器的方式:此时s3和s4保存的是地址值,是数据在堆空间中开辟空间之后对应的地址值
//通过该方式,在内存中创建了两个对象(1.堆空间中new创建的对象 2.char[]对应的常量池中的数据
String s3 = new String("javaEE");
String s4 = new String("javaEE");
System.out.println(s1==s2);//true
System.out.println(s3==s4);//false
System.out.println(s1==s3);//false
}
}
String不同拼接操作的对比
public class StringTest {
/*
常量与常量的拼接结果在常量池中,且常量池中不会存在相同的变量
只要其中有一个是变量,结果就在堆中
如果拼接的结果调用intern()方法,返回值就在常量池中
*/
@Test
public void test1(){
String s1="javaEE";
String s2="hadoop";
String s3="javaEEhadoop";
String s4="javaEE"+"hadoop";
String s5=s1+"hadoop"; //只要有变量名参与的拼接,则都放在堆空间
String s6="javaEE"+s2;
String s7=s1+s2;
String s8=s5.intern();//返回值得到的s8使用的是常量池中已经存在的"javaEEhadoop"
System.out.println(s3==s4);//true
System.out.println(s3==s5);//false
System.out.println(s3==s6);//false
System.out.println(s3==s7);//false
System.out.println(s5==s6);//false
System.out.println(s6==s7);//false
System.out.println(s3==s8);//true
}
}
String的一道面试题
public class StringTest {
String str = new String("good"); //开辟在堆空间
char[] ch={'t','e','s','t'};
public void change(String str,char[] ch){
str = "test ok"; //String不可变性
ch[0] = 'b';
}
public static void main(String[] args) {
StringTest ex = new StringTest();
ex.change(ex.str,ex.ch);
System.out.println(ex.str);//good
System.out.println(ex.ch);//best
}
}
JVM中涉及字符串的内存结构
String常用方法1
- 重点要理解String的不变性
public class StringMethodTest {
@Test
public void test1(){
String s1="helloworld";
System.out.println(s1.length());
System.out.println(s1.charAt(2));
System.out.println(s1.charAt(8));
System.out.println(s1.isEmpty());
System.out.println(s1.toLowerCase());
String s2 = s1.toUpperCase();
System.out.println(s1); //字符串的不可变性
System.out.println(s2);
System.out.println("---------------");
String s3 = " hello world ";
String s4 = s3.trim();
System.out.println(s4);
}
@Test
public void test2(){
String s1 = "helloworld";
String s2 = "Helloworld";
System.out.println(s1.equals(s2));//false
System.out.println(s1.equalsIgnoreCase(s2));//true
String s3 = "abc";
String s4 = s3.concat("def");
System.out.println(s4);
String s5 = "abc";
String s6 = "abf";
System.out.println(s5.compareTo(s6));//-3
String s7 = "beijingshangguigu";
String s8 = s7.substring(3);
System.out.println(s7.substring(0,6)); //左闭右开
System.out.println(s7);
System.out.println(s8);
}
}
String常用方法2
public class StringMethodTest {
@Test
public void test1(){
String str1 = "helloworld";
boolean b1 = str1.endsWith("d");
boolean b2 = str1.endsWith("rld");
System.out.println(b1);
System.out.println(b2);
boolean b3 = str1.startsWith("He");
System.out.println(b3);//false
boolean b4 = str1.startsWith("ll",2);
System.out.println(b4);
System.out.println(str1.contains("world"));
System.out.println(str1.indexOf("world"));
System.out.println(str1.indexOf("LOL"));//没找到则返回-1
System.out.println(str1.indexOf("lo",5));//-1
String str2 = "hellorworld";
System.out.println(str2.lastIndexOf("or"));//返回7
System.out.println(str2.lastIndexOf("or",6));//返回4
}
}
String常用方法3
public class StringMethodTest {
@Test
public void test1(){
String str1="beijingshangguigu";
String str2 = str1.replace('b','d');
String str3 = str1.replace("beijing","shanghai");
System.out.println(str1);
System.out.println(str2);
System.out.println(str3);
}
}
String与基本数据类型包装类的转换
public class StringTest {
/*
String与基本数据类型、包装类之间的转换
String-->基本数据类型、包装类:调用包装类的静态方法parseXxx(str)
基本数据类型、包装类-->String:调用String重载的valueOf(xxx)方法
*/
@Test
public void test1(){
String str1 = "123";
int num = Integer.parseInt(str1);
System.out.println(num);
String str2 = String.valueOf(num);
System.out.println(str2);
String str3 = str2 + "";
}
}
String与char[]之间的转换
public class StringTest {
/*
String与char[]之间的转换
String-->char[]:调用String的toCharArray()方法
char[]-->String:调用String的构造器
*/
@Test
public void test1(){
String str1 = "abc123";
char[] charArray = str1.toCharArray();
for (int i = 0; i < charArray.length; i++) {
System.out.println(charArray[i]);
}
char[] arr = new char[]{'h','e','l','l','o'};
String str2 = new String(arr);
System.out.println(str2);
}
}
String与byte[]之间的转换
public class StringTest {
/*
String与byte[]之间的转换
String-->byte[]:调用String的getBytes()方法
byte[]-->String:调用String的构造器
编码:字符串-->字节
解码:字节-->字符串 是编码的逆过程
解码时使用的字符集必须与编码时使用的字符集一致,否则会乱码
*/
@Test
public void test1() throws UnsupportedEncodingException {
String str1 = "abc123中国";
byte[] bytes = str1.getBytes(); //默认UTF-8
byte[] bytes1 = str1.getBytes("gbk");//指定编码集
System.out.println(Arrays.toString(bytes));
System.out.println(Arrays.toString(bytes1));
String str2 = new String(bytes);//默认UTF-8
System.out.println(str2);
}
}
StringBuffer和StringBuilder的介绍
public class StringBufferBuilderTest {
/*
String、StringBuffer、StringBuilder三者的异同
String:不可变的字符序列 底层使用final char[]存储
StringBuffer:可变的字符序列;线程安全的,效率低 底层使用char[]存储
StringBuilder:可变的字符序列;jdk5.0新增的,线程不安全,效率高 底层使用char[]存储
*/
@Test
public void test(){
StringBuffer sb1 = new StringBuffer("abc");
sb1.setCharAt(0,'m');
System.out.println(sb1);
}
}
StringBuffer的源码分析
public class StringBufferBuilderTest {
/*
String、StringBuffer、StringBuilder三者的异同
String:不可变的字符序列 底层使用final char[]存储
StringBuffer:可变的字符序列;线程安全的,效率低 底层使用char[]存储
StringBuilder:可变的字符序列;jdk5.0新增的,线程不安全,效率高 底层使用char[]存储
源码分析:
String str = new String(); //new char[0]
String str1 = new String("abc"); //new char[]{'a','b','c'}
StringBuffer sb1 = new StringBuffer();//char[] value = new char[16] 底层创建了一个长度是16的字符数组
sb1.append('a');//value[0]='a';
sb1.append('b');//value[1]='b';
StringBuffer sb2 = new StringBuffer("abc");//char[] value = new char["abc".length()+16]
//问题1:System.out.println(sb2.length());//3
//问题2:扩容问题:如果要添加的数据 底层数组盛不下了,就需要扩容底层的数组
默认情况下,扩容为原来的2倍+2,同时将原有数组中的元素复制到新数组中
开发中建议使用StringBuffer(int capacity)或StringBuilder(int capacity)
*/
@Test
public void test(){
StringBuffer sb1 = new StringBuffer("abc");
sb1.setCharAt(0,'m');
System.out.println(sb1);
StringBuffer sb2 = new StringBuffer();
System.out.println(sb2.length());//0
}
}
StringBuffer的常用类
public class StringBufferBuilderTest {
@Test
public void test(){
//CRUD、长度
StringBuffer sb1 = new StringBuffer("abc");
sb1.append('d');
sb1.append('e');
System.out.println(sb1.charAt(2));
System.out.println(sb1);
sb1.delete(2,4);
System.out.println(sb1);
sb1.replace(0,2,"hello");
System.out.println(sb1);
sb1.insert(2,"www");
System.out.println(sb1);
sb1.reverse();
System.out.println(sb1);
String s= sb1.substring(1,3);
System.out.println(s);
}
}
String、StringBuffer、StringBuilder效率对比
StringBuilder效率最高
StringBuffer其次
String最差