(一)Java常用类之字符串String | 【奔跑吧!JAVA】

1、String的特性

(1)String代表字符串。Java程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现。
(2)字符串是常量,用双引号("")引起来表示。它们的值在创建之后不能更改。
(3)String类是一个final类,代表不可变的字符序列并且不可被继承。
(4)String类实现了Serializable接口:表示字符串是支持序列化的。
(5)String类实现了Comparable接口:表示String可以比较大小
(6)String类内部定义了final char[] value用于存储字符串数据。
(7)通过字面量的方式(区别于new给一个字符串赋值,此时的字符串值声明在字符串常量池中)
(8)字符串常量池中是不会存储相同内容(使用String类的equals()比较,返回true)的字符串的。

String源码截图

2、String对象的创建方式

public class StringTest {
    public static void main(String[] args) {
        // 1、字面量方式创建
        String s0 = "hello";
        // 2、通过new的方式创建空字符串,本质上是this.value = new char[0];
        String s1 = new String();
        // 3、通过new的方式,根据其它字符串创建新字符串,本质上是this.value = original.value;
        String s2 = new String("hello");
        // 4、通过字符数组的方式创建字符串,本质上是this.value = Arrays.copyOf(value, value.length);
        char[] c1 = {'h', 'e', 'l', 'l', 'o'};
        String s3 = new String(c1);
        // 5、通过字符数组的方式根据开始索引和需要的长度创建字符串,本质上是this.value = Arrays.copyOf(value, value.length);
        String s4 = new String(c1, 0, 2);
    }
}

说明:其它创建方式详见JavaAPI文档

3、String内存分配

String str1 = “abc”;与String str2 = new String(“abc”);的区别?
String内存分配

4、String特性举例

public class StringTest {
    public static void main(String[] args) {
        String s1 = "Hello";
        final String s11 = "Hello"; //s11:常量
        String s2 = "World";
        String s3 = "HelloWorld";
        String s4 = "Hello" + "World";
        String s5 = s1 + "World";
        String s55 = s11 + "World";
        String s6 = "Hello" + s2;
        String s7 = s1 + s2;

        System.out.println(s3 == s4);//true
        System.out.println(s3 == s5);//false
        System.out.println(s3 == s55);//true
        System.out.println(s3 == s6);//false
        System.out.println(s3 == s7);//false
        System.out.println(s5 == s6);//false
        System.out.println(s5 == s7);//false
        System.out.println(s6 == s7);//false

        // 返回值得到的s8使用的常量值中已经存在的“HelloWorld”
        String s8 = s6.intern();
        System.out.println(s3 == s8);//true
    }
}

5、String使用陷阱

String s1 = "a"; 
	说明:在字符串常量池中创建了一个字面量为"a"的字符串。

s1 = s1 + "b"; 
	说明:实际上原来的“a”字符串对象已经丢弃了,现在在堆空间中产生了一个字符串s1+"b"(也就是"ab")。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能。

String s2 = "ab";
	说明:直接在字符串常量池中创建一个字面量为"ab"的字符串。

String s3 = "a" + "b";
	说明:s3指向字符串常量池中已经创建的"ab"的字符串。

String s4 = s1.intern();
	说明:堆空间的s1对象在调用intern()之后,会将常量池中已经存在的"ab"字符串赋值给s4。

6、String常用方法

6.1、字符串基本操作

public class StringTest {
    public static void main(String[] args) {
        //定义一个字符串
        String str = " Hello World ";

        // 1、length():返回字符串的长度: return value.length
        int length = str.length();
        System.out.println("字符串的长度为:" + length);

        // 2、charAt():返回某索引处的字符return value[index]
        char ch = str.charAt(4);
        System.out.println("字符串中的第5个字符为:" + ch);

        // 3、isEmpty():判断是否是空字符串:return value.length == 0
        System.out.println("字符串是否为空:" + str.isEmpty());

        // 4、toLowerCase():使用默认语言环境,将 String 中的所字符转换为小写
        System.out.println("字符串转换为小写:" + str.toLowerCase());

        // 5、toUpperCase():使用默认语言环境,将 String 中的所字符转换为大写
        System.out.println("字符串转换为大写:" + str.toUpperCase());

        // 6、trim():返回字符串的副本,忽略前导空白和尾部空白
        System.out.println("忽略前导空白和尾部空白:" + str.trim());

        // 7、concat(String str):将指定字符串连接到此字符串的结尾。 等价于用“+”
        System.out.println("拼接字符串:" + str.concat("!!!"));
    }
}

6.2、字符串比较

public class StringTest {
    public static void main(String[] args) {
        //定义两个字符串
        String str1 = "Hello World";
        String str2 = "hello world";
        // 1、compareTo(String anotherString):比较两个字符串的大小
        // 返回值大于0则str1大于str2,返回值等于0则str1等于str2,返回值小于0则str1小于str2
        System.out.println("str1和str2比较结果:" + str1.compareTo(str2));

        // 2、compareToIgnoreCase(String str):比较两个字符串的大小,忽略大小写
        // 返回值大于0则str1大于str2,返回值等于0则str1等于str2,返回值小于0则str1小于str2
        System.out.println("str1和str2忽略大小写比较结果:" + str1.compareToIgnoreCase(str2));

        // 3、equals(Object obj):比较字符串的内容是否相同
        // 返回值等于true则str1等于str2,返回值等于false则str1不等于str2
        System.out.println("str1和str2比较结果:" + str1.equals(str2));

        // 4、equalsIgnoreCase(String anotherString):与equals方法类似,忽略大小写
        // 返回值等于true则str1等于str2,返回值等于false则str1不等于str2
        System.out.println("str1和str2忽略大小写比较结果:" + str1.equalsIgnoreCase(str2));
    }
}

6.3、字符串截取

public class StringTest {
    public static void main(String[] args) {
        String str = "hello world !!!";

        // 1、substring(int beginIndex):返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。
        System.out.println(str.substring(6));

        // 2、substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
        System.out.println(str.substring(6, 11));
    }
}

6.4、字符串查找

public class StringTest {
    public static void main(String[] args) {
        String str = "hello hello world !!!";

        // 1、indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引
        System.out.println(str.indexOf("hello"));

        // 2、indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
        System.out.println(str.indexOf("hello", 5));

        // 3、lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引
        System.out.println(str.lastIndexOf("hello"));

        // 4、lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
        System.out.println(str.lastIndexOf("hello", 5));
    }
}

6.5、字符串替换

public class StringTest {
    public static void main(String[] args) {
        String str = "hello world !!!";

        // 1、replace(char oldChar, char newChar):返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所 oldChar 得到的。
        System.out.println(str.replace('l', 'm'));

        // 2、replace(CharSequence target, CharSequence replacement):使用指定的字面值替换序列替换此字符串所匹配字面值目标序列的子字符串。
        System.out.println(str.replace("world", "china"));

        // 3、replaceAll(String regex, String replacement):使用给定的 replacement 替换此字符串所匹配给定的正则表达式的子字符串。
        String str1 = "www.baidu.com";
        System.out.println("匹配成功返回值:" + str1.replaceAll("(.*)baidu(.*)", "taobao"));
        System.out.println("匹配失败返回值:" + str1.replaceAll("(.*)jingdong(.*)", "taobao"));

        // 4、replaceFirst(String regex, String replacement):使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
        String str2 = "hello world, I am from world。";
        System.out.println("返回值:" + str2.replaceFirst("world", "china"));
        System.out.println("返回值:" + str2.replaceFirst("(.*)world(.*)", "china"));
    }
}

6.6、字符串匹配

public class StringTest {
    public static void main(String[] args) {
        String str = "www.baidu.com";

        // 1、matches(String regex):告知此字符串是否匹配给定的正则表达式。
        System.out.println(str.matches("(.*)baidu(.*)"));

        // 2、endsWith(String suffix):测试此字符串是否以指定的后缀结束
        System.out.println(str.endsWith(".com"));

        // 3、startsWith(String prefix):测试此字符串是否以指定的前缀开始
        System.out.println(str.startsWith("www."));

        // 4、startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始
        System.out.println(str.startsWith("www.", 3));

        // 5、contains(CharSequence s):当且仅当此字符串包含指定的 char 值序列时,返回 true
        System.out.println(str.contains("baidu"));
    }

6.7、字符串拆分

public class StringTest {
    public static void main(String[] args) {
        String str = "www.baidu.com";

        // 1、split(String regex):根据给定正则表达式的匹配拆分此字符串。
        String[] strs1 = str.split("\\.");
        System.out.print("拆分结果:");
        for (int i = 0; i < strs1.length; i++) {
            System.out.print(strs1[i] + " ");
        }
        System.out.println();

        // 2、split(String regex, int limit):根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中。
        String[] strs2 = str.split("\\.", 2);
        System.out.print("拆分结果:");
        for (int i = 0; i < strs2.length; i++) {
            System.out.print(strs2[i] + " ");
        }
        System.out.println();
    }
}

7、String与其它结构的转换

7.1、与基本数据类型、包装类之间的转换

String --> 基本数据类型、包装类:调用包装类的静态方法:parseXxx(str)
基本数据类型、包装类 --> String:调用String重载的valueOf(xxx)
public class StringTest {
    public static void main(String[] args) {
        // 字符串转基本数据类型
        String str1 = "123";
        int num = Integer.parseInt(str1);

        // 基本数据类型转字符串
        String str2 = String.valueOf(num);
        String str3 = num + "";
    }
}

7.2、与字符数组之间的转换

String --> char[]:调用String的toCharArray()
char[] --> String:调用String的构造器
public class StringTest {
    public static void main(String[] args) {
        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);
    }
}

7.3、与字节数组之间的转换

编码:String --> byte[]:调用String的getBytes()
解码:byte[] --> String:调用String的构造器

编码:字符串 -->字节  (看得懂的数据 --> 看不懂的二进制数据)
解码:编码的逆过程,字节 --> 字符串 (看不懂的二进制数据 --> 看得懂的数据)

说明:解码时,要求解码使用的字符集必须与编码时使用的字符集一致,否则会出现乱码。
public class StringTest {
    public static void main(String[] args) throws UnsupportedEncodingException {
        String str1 = "abc123中国";
        //使用默认的字符集,进行编码。
        byte[] bytes = str1.getBytes();
        System.out.println(Arrays.toString(bytes));

        //使用gbk字符集进行编码。
        byte[] gbks = str1.getBytes("gbk");
        System.out.println(Arrays.toString(gbks));

        //使用默认的字符集,进行解码。
        String str2 = new String(bytes);
        System.out.println(str2);

        String str3 = new String(gbks);
        //出现乱码。原因:编码集和解码集不一致!
        System.out.println(str3);

        String str4 = new String(gbks, "gbk");
        //没出现乱码。原因:编码集和解码集一致!
        System.out.println(str4);
    }
}

7.4、与StringBuffer、StringBuilder之间的转换

String --> StringBuffer、StringBuilder:调用StringBuffer、StringBuilder构造器
StringBuffer、StringBuilder --> String:调用String构造器;StringBuffer、StringBuilder的toString()
public class StringTest {
    public static void main(String[] args) {
        String str1 = "hello world";

        // String转StringBuffer、StringBuilder
        StringBuffer sb1 = new StringBuffer(str1);
        StringBuilder sb2 = new StringBuilder(str1);

        // 字符数组转字符串
        String str2 = sb1.toString();
        String str3 = sb2.toString();
    }
}

8、JVM中字符串常量池存放位置说明

jdk 1.6 (jdk 6.0 ,java 6.0):字符串常量池存储在方法区(永久区)
jdk 1.7:字符串常量池存储在堆空间
jdk 1.8:字符串常量池存储在方法区(元空间)

【奔跑吧!JAVA】有奖征文火热进行中:https://bbs.huaweicloud.com/blogs/265241

(完)