深入理解java中String类

创建字符串

创建字符串常见3中方式

  1. 直接赋值
String str = "Hello";
  1. new对象赋值
String str2 = new String("Hello");
  1. 数组转换字符串
char[] array = {
    
    'H', 'e', 'l','l','o'};
String str3 = new String(array);

三种赋值的内存结构

在这里插入图片描述

字符串的比较

那么这个代码的结果时怎样的呢?

        String str = "Hello";
        String str2 = new String("Hello");
        char[] array = {
    
    'H', 'e', 'l','l','o'};
        String str3 = new String(array);

        System.out.println(str == str2);
        System.out.println(str == str3);
        System.out.println(str2 == str3);

在这里插入图片描述

其实根据上面的结构图不难看出,每个引用都是不相同的,引用所指向的地址不同,则指向的不是同一对象。

由此可见:
String 使用 “ == ”比较并不是在比较字符串内容, 而是比较两个引用是否是指向同一个对象


同理也可以判断这些输出结果

        String str1 = "abcde";
        
        String str2 = new String("abcde");
        System.out.println(str1 == str2);   //false
        
        String str3 = "abc" + "de"; //编译时 就进行了拼接,变为"abcde"
        System.out.println(str3 == str1);   //true
        
        String str4 = new String("abc") + new String("de");
        System.out.println(str1 == str4);   //false;
        
        String str5 = new String("abc") + "de";
        System.out.println(str5 == str1);   //false

        System.out.println(str4 == str5);   //false

equals方法

“==”号是用来比较两个对象是否相同,那么如果想比较对象里的内容是否相同,该怎么办呢?

String中有equals方法,可以比较两者里的内容是否相等

        String a = new String("123");
        String b = "123";
        System.out.println(a.equals(b));	//true

字符串常量池

String类的两种实例化操作, 直接赋值和 new 一个新的 String

1. 直接赋值

String str1 = "hello" ;
String str2 = "hello" ;
String str3 = "hello" ;
System.out.println(str1 == str2); // true
System.out.println(str1 == str3); // true
System.out.println(str2 == str3); // true

在这里插入图片描述
可以发现此时并没有开辟新的堆内存空间,那是因为

在JVM底层实际上会自动维护一个对象池(字符串常量池)

  • 如果现在采用了直接赋值的模式进行String类的对象实例化操作,那么该实例化对象(字符串内容)将自动保存到这个对象池之中.
  • 如果下次继续使用直接赋值的模式声明String类对象,此时对象池之中如若有指定内容,将直接进行引用
  • 如若没有,则开辟新的字符串对象而后将其保存在对象池之中以供下次使用

2. 采用构造方法

String str = new String("hello") ;

在这里插入图片描述
这样的做法有两个缺点:

  • 如果使用String构造方法就会开辟两块堆内存空间,并且其中一块堆内存将成为垃圾空间(字符串常量 “hello” 也是一个匿名对象, 用了一次之后就不再使用了, 就成为垃圾空间, 会被 JVM 自动回收掉)
  • 字符串共享问题. 同一个字符串可能会被存储多次, 比较浪费空间

但是我们可以使用 String 的 intern方法来手动把 String 对象加入到字符串常量池中

// 该字符串常量并没有保存在对象池之中
String str1 = new String("hello") ;
String str2 = "hello" ;
System.out.println(str1 == str2);	//false

String str1 = new String("hello").intern() ;
String str2 = "hello" ;
System.out.println(str1 == str2);	//true

在这里插入图片描述


总结:解释String类中两种对象实例化的区别

  • 直接赋值:只会开辟一块堆内存空间,并且该字符串对象可以自动保存在对象池中以供下次使用
  • 构造方法:会开辟两块堆内存空间,不会自动保存在对象池中,可以使用intern()方法手工入池

理解字符串不可变

字符串是一种不可变对象. 它的内容不可改变

String str = "hello" ;
str = str + " world" ;
str += "!!!" ;
System.out.println(str);

这样一个代码虽然能执行处一个正确的结果,但是!!!

其内存发生了巨大的变化,如下图

在这里插入图片描述
因为字符串是不可变的,所以它会拼接出很多用不到的内存,最后只用到最后拼接好的字符串,从而导致浪费内存


那么如果实在需要修改字符串, 例如, 现有字符串 str = “Hello” , 想改成 str = “hello” , 该怎么办?

  1. 借助原字符串, 创建新的字符串
String str = "Hello";
str = "h" + str.substring(1);
System.out.println(str);
// 执行结果  hello
  1. 使用 “反射” 这样的操作可以破坏封装, 访问一个类内部的 private 成员(这里就不详细赘述了)

字符,字节,字符串

1、字符与字符串

NO. 方法名称 类型 描述
1. public String(char value[]) 构造 将字符数组的所有内容变为字符串
2. public String(char value[], int offset, int count) 构造 将部分字符数组中的内容变为字符串
3. public char charAt(int index) 普通 取得指定索引位置的字符,索引从0开始
4. public char[] toCharArray() 普通 将字符串变为字符数组返回

  1. public String(char value[])----(字符数组)
    将字符数组的所有内容变为字符串
        char[] value = {
    
    'h','e','l','l','o'};
        String a = new String(value);
        System.out.println(a);  //hello

  1. public String(char value[], int offset, int count)----(字符数组,区间首位置,区间尾位置)
        char[] value = {
    
    'h','e','l','l','o'};
        String a = new String(value,1,3);
        System.out.println(a);  //ell

  1. public char charAt(int index)----(下标位置)
        String b = "hello";
        System.out.println(b.charAt(1));    //e

  1. public char[] toCharArray()
		String b = "hello";
        char[] c = b.toCharArray();
        System.out.println(Arrays.toString(c)); //[h, e, l, l, o]

2、字节与字符串

NO. 方法名称 类型 描述
1. public String(byte bytes[]) 构造 将字节数组变为字符串
2. public String(byte bytes[], int offset, int lengrh) 构造 将部分字节数组中的内容变为字符串
3. public byte[] getBytes() 普通 将字符串以字节数组的形式返回
4. public byte[] getBytes(String charsetName) throw unsupportedEncodingException 普通 编码转换处理

  1. String(byte bytes[])----(字节数组)
        byte[] d = {
    
    97,98,99,100};
        String e = new String(d);
        System.out.println(e);  //abcd

  1. String(byte bytes[], int offset, int lengrh)—(字节数组,区间首位置,区间尾位置)
        byte[] d = {
    
    97,98,99,100};
        String e = new String(d,1,2);
        System.out.println(e);  //bc

  1. byte[] getBytes()
        String f = "abcde";
        byte[] g = f.getBytes();
        System.out.println(Arrays.toString(g)); //[97, 98, 99, 100, 101]

  1. public byte[] getBytes(String charsetName) throw unsupportedEncodingException
    可以通过不同的编码格式来转换对应的字节值
        String h = "xing";
        try {
    
    
            byte[] bytes = h.getBytes("utf8");  //编码格式,还可以写gbk等
        } catch (UnsupportedEncodingException e) {
    
    
            e.printStackTrace();    //[97, 98, 99, 100, 101]
        }

3、总结

  • byte[] 是把 String 按照一个字节一个字节的方式处理, 这种适合在网络传输, 数据存储这样的场景下使用.更适合针对二进制数据来操作.
  • char[] 是吧 String 按照一个字符一个字符的方式处理, 更适合针对文本数据来操作, 尤其是包含中文的时候

字符串常见操作

1、字符串比较

NO. 方法名称 类型 描述
1. public boolean equals(Object anObject) 普通 区分大小写比较
2. public boolean equalsIanoreCase(String anoterString) 普通 不区分大小写比较
3. public int compareTo(String anotherString) 普通 比较两个字符串大小关系

  1. public boolean equals(Object anObject) ----(比较的对象)
        String a = "abcd";
        String b = "abcd";
        System.out.println(a.equals(b));    //true

  1. public boolean equalsIanoreCase(String anoterString)----(比较的对象)
        String a = "AbCd";
        String b = "abcd";
        System.out.println(a.equalsIgnoreCase(b));  //true

  1. public int compareTo(String anotherString)----(比较的对象)
        String a = "abcd";
        String b = "abcd";
        System.out.println(a.compareTo(b)); //相同返回 0

		String c = "abcde";
        String d = "abcd";
        System.out.println(c.compareTo(d)); //a > b  返回大于0的数,此例子返回1

		String e = "abcd";
        String f = "abcdfg";
        System.out.println(e.compareTo(f)); //a < b  返回小于0的数,此例子为-2

2、字符串查找

NO. 方法名称 类型 描述
1. public boolean contains(CharSequence s) 普通 判断一个子字符是否存在
2. public int indexOf(String str) 普通 从头开始查找指定字符串的位置,查到了返回位置的开始索引,如果查不到返回-1
3. public int indexOf(String str, int fromIndex) 普通 从指定位置开始查找子字符串位置
4. public int lastIndexOf(String str) 普通 由后向前查找子字符串位置
5. public int lastIndexOf(String str, int fromIndex) 普通 从指定位置有后向前查找
6. public boolean startsWith(String prefix) 普通 判断是否以指定字符串开头
7. public boolean startsWith(String prefix, int toffset) 普通 从指定位置开始判断是否以指定字符串开头
8. public boolean endsWith(String suffix) 普通 判断是否以指定字符串结尾
  1. public boolean contains(CharSequence s)----(查找的字符串接口)
        String a = "abcdef";
        String b = "bcd";
        String c = "dcb";
        System.out.println(a.contains(b));  //true
        System.out.println(a.contains(c));  //false

  1. public int indexOf(String str)----(查找的字符串)
        String a = "abcdef";
        String b = "bcd";
        String c = "dcb";
        System.out.println(a.indexOf(b));  //有,返回第一个字母下标 1
        System.out.println(a.indexOf(c));  //无,返回-1

  1. public int indexOf(String str, int fromIndex)----(查找的字符串,开始位置下标)
        String a = "abcdef";
        String b = "cd";
        System.out.println(a.indexOf(b,2));  //有,返回第一个字母下标 2
        System.out.println(a.indexOf(b,3));  //从fromIndex往后找,没找到,返回-1

  1. public int lastIndexOf(String str)----(查找的字符串)
        String c = "abababeee";
        System.out.println(c.lastIndexOf("ab"));    //从后往前,第一个ab在四号下标,返回4

  1. public int lastIndexOf(String str, int fromIndex)----(查找的字符串,开始位置下标)
        String c = "abababeee";
        System.out.println(c.lastIndexOf("ab",3));    //从fromIndex往前,第一个ab在二号下标,返回2

  1. public boolean startsWith(String prefix)----(查找的字符串)
        String d = "beatuiful";
        System.out.println(d.startsWith("bea"));    //是"bea"开头,返回true

  1. public boolean startsWith(String prefix, int toffset)----(查找的字符串,开始位置下标)
        String d = "beatuiful";
        System.out.println(d.startsWith("atu",2));    //从toffset下标开始,是"atu"开头,返回true

  1. public boolean endsWith(String suffix)
        String d = "beatuiful";
        System.out.println(d.endsWith("ful"));  //从后往前,最后是"ful"结尾,返回true

3、字符串替换

NO. 方法名称 类型 描述
1. public String replaceAll(String regex,String replacement) 普通 替换所有指定内容
2. public String replaceFirst(String regex, String replacement) 普通 替换首个内容
  1. public String replaceAll(String regex,String replacement)----(子字符串,想要替换的字符串)
        String f = "abababababcde";
        String h = f.replaceAll("ab", "hh");
        System.out.println(h);	//hhhhhhhhhhcde

  1. public String replaceFirst(String regex, String replacement)----(子字符串,想要替换的字符串)
        String f = "abababababcde";
        String h = f.replaceFirst("ab", "hh");
        System.out.println(h);  //只替换第一次出现的,返回hhababababcde

4、字符串拆分

NO. 方法名称 类型 描述
1. public String[] split(String regex) 普通 将字符串全部拆分
2. public String[] split(String regex, int limit) 普通 将字符串部分拆分,该数组长度就是limit极限
  1. public String[] split(String regex)
        String str = "hello world hello xingxing" ;
        String[] result = str.split(" ") ;  //按空格拆分
        System.out.println(Arrays.toString(result));	//[hello, world, hello, xingxing]

  1. public String[] split(String regex, int limit)
        String str = "hello world hello xingxing" ;
        String[] result = str.split(" ",3) ;
        System.out.println(Arrays.toString(result));	//最多数组空间为3,所以为[hello, world, hello xingxing]

5、字符串截取

NO. 方法名称 类型 描述
1. public String substring(int beginIndex) 普通 从指定索引截取到结尾
2. public String substring(int beginIndex, int endIndex) 普通 截取部分内容

  1. public String substring(int beginIndex) ----(起始位置下标)
        String str = "helloworld" ;
        System.out.println(str.substring(5));   //world

  1. public String substring(int beginIndex, int endIndex)----(起始位置下标,结束位置下标)
        String str = "helloworld" ;
        System.out.println(str.substring(0, 5));    //hello

6、其他操作方法

NO. 方法名称 类型 描述
1. public String trim() 普通 去掉字符串中的左右空格,保留中间空格
2. public String toUpperCase() 普通 字符串转大写
3. public String toLowerCase() 普通 字符串转小写
4. public native String intern() 普通 字符串入池操作
5. public String concat(String str) 普通 字符串连接,等同于“+”,不入池
6. public int length() 普通 取得字符串长度
7. public boolean isEmpty() 普通 判断是否为空字符串,但不是null,而是长度为0
  1. public String trim()
        String str = " hello world " ;
        System.out.println(str.trim()); //去掉了首尾空格hello world

  1. public String toUpperCase()
        String str = "hello world" ;
        System.out.println(str.toUpperCase()); //HELLO WORLD

  1. public String toLowerCase()
        String str = "HELLO WORLD" ;
        System.out.println(str.toLowerCase()); //hello world

  1. public native String intern()
String str1 = new String("hello").intern() ;
String str2 = "hello" ;
System.out.println(str1 == str2);	//true

  1. public String concat(String str)----(想要拼接的字符串)
        String a = "hello";
        String b = "world";
        System.out.println(a.concat(b));    //helloworld

  1. public int length()
        String a = "hello";
        System.out.println(a.length());	//5

  1. public boolean isEmpty()
        String str1 = "";   //str1指向的对象为空
        System.out.println(str1.isEmpty());  //true
        String str2 = null; //str2不指向任何对象
        System.out.println(str2.isEmpty()); //空指针异常

StringBuffer 和 StringBuilder

String 和 StringBuffer 、StringBuilder的区别

  1. 后两者包含了一些String没有的方法,比如reverse方法
  2. 后两者是可变的,String是不可变的。String每次拼接,都会产生新的对象。后两者每次的拼接都返回的是this
  3. StringBuilder StringBuilder区别:
    StringBuilder和String出现在单线程情况下
    StringBuffer因为有synchronized关键字,所以一般出现在多线程情况下。
  4. StringBuilder和String之间的区别:
    String的拼接+ 会被优化,优化为StringBuilder . append了
    在循环当中,不可以使用String直接进行拼接,这样会产生大量的临时对象,包括优化后的StringBuilder对象
StringBuffer sb = new StringBuffer();
sb.append("Hello").append("World");
System.out.println(sb);

猜你喜欢

转载自blog.csdn.net/starry1441/article/details/113945380