String类
String 类代表字符串,Java 程序中的所有字符串文字(例如“abc”)都被实现为此类的实例。也就是说,Java 程序中所有的双引号字符串,都是 String 类的对象。String 类在 java.lang 包下,所以使用的时候不需要导包!
String类的特点
- String类:代表字符串。Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现。String:字符串,使用一对""引起来表示。
- String是一个final类,代表不可变的字符序列。不可被继承。
- 字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改
- 虽然 String 的值是不可变的,使用=号创建的字符串对象,都在常量池中,它们可以被共享。
- 字符串效果上相当于字符数组( char[] ),但是底层原理是字节数组( byte[] )
- 通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。字符串常量池中是不会存储相同内容的字符串的。
- .String实现了Serializable接口:表示字符串是支持序列化的。 实现了Comparable接口:表示String可以比较大小
String:代表不可变的字符序列。简称:不可变性。体现下面几个方面
- 当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。
- 当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
- 当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
常用构造方法(String不止这些构造器)
示例:
package com.wrg; /* String构造方法: public String():创建一个空白字符串对象,不含有任何内容 public String(char[] chs):根据字符数组的内容,来创建字符串对象 public String(byte[] bys):根据字节数组的内容,来创建字符串对象 String s = “abc”; 直接赋值的方式创建字符串对象,内容就是abc 推荐使用直接赋值的方式得到字符串对象 */ public class StringDemo { public static void main(String[] args) { //public String():创建一个空白字符串对象,不含有任何内容 String s1 = new String(); System.out.println("s1:" + s1);//s1: //public String(char[] chs):根据字符数组的内容,来创建字符串对象 char[] chs = {'a', 'b', 'c'}; String s2 = new String(chs); System.out.println("s2:" + s2);//s2:abc //public String(byte[] bys):根据字节数组的内容,来创建字符串对象 byte[] bys = {97, 98, 99}; String s3 = new String(bys); System.out.println("s3:" + s3);//s3:abc //String s = “abc”; 直接赋值的方式创建字符串对象,内容就是abc String s4 = "abc"; System.out.println("s4:" + s4);//s4:abc } }
创建字符串对象两种方式的区别
- 通过构造方法创建:通过 new 创建的字符串对象,每一次 new 都会申请一个内存空间,虽然内容相同,但是地址值不同。
字符串非常量对象 存储在堆中。
- 直接赋值方式创建:以“”方式给出的字符串,只要字符序列相同(顺序和大小写),无论在程序代码中出现几次,JVM 都只会建立一个 String 对象,并在字符串池中维护字符串常量存储在字符串常量池,目的是共享。
示例:
package demo01; /* 字符串常量池:程序当中直接写上的双引号字符串,就在字符串常量池中。 对于基本类型来说,==是进行数值的比较。 对于引用类型来说,==是进行【地址值】的比较。 */ public class Demo02StringPool { public static void main(String[] args) { String str1 = "abc"; String str2 = "abc"; char[] charArray = {'a', 'b', 'c'}; String str3 = new String(charArray); System.out.println(str1 == str2); // true System.out.println(str1 == str3); // false System.out.println(str2 == str3); // false } }
注意:
- 常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
- 字符串拼接只要其中有一个是变量拼接,结果就在堆中
- 如果拼接的结果调用intern()方法,返回值就在常量池中
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。
面试题:String s = new String("abc");方式创建对象,在内存中创建了几个对象?
- 答:两个:一个是堆空间中new结构,另一个是char[]对应的常量池中的数据:"abc"
字符串常用方法,其他不常用的方法可以查询API学习
判断功能的方法
- public boolean equals (Object anObject) :将此字符串与指定对象进行比较。
- public boolean equalsIgnoreCase (String anotherString) :将此字符串与指定对象进行比较,忽略大小写。
package demo02; /* ==是进行对象的地址值比较,如果确实需要字符串的内容比较,可以使用两个方法: public boolean equals(Object obj):参数可以是任何对象,只有参数是一个字符串并且内容相同的才会给true;否则返回false。 注意事项: 1. 任何对象都能用Object进行接收。 2. equals方法具有对称性,也就是a.equals(b)和b.equals(a)效果一样。 3. 如果比较双方一个常量一个变量,推荐把常量字符串写在前面。 推荐:"abc".equals(str) 不推荐:str.equals("abc") public boolean equalsIgnoreCase(String str):忽略大小写,进行内容比较。 */ public class Demo01StringEquals { public static void main(String[] args) { String str1 = "Hello"; String str2 = "Hello"; char[] charArray = {'H', 'e', 'l', 'l', 'o'}; String str3 = new String(charArray); System.out.println(str1.equals(str2)); // true System.out.println(str2.equals(str3)); // true System.out.println(str3.equals("Hello")); // true System.out.println("Hello".equals(str1)); // true String str4 = "hello"; System.out.println(str1.equals(str4)); // false System.out.println("================="); String str5 = null; System.out.println("abc".equals(str5)); // 推荐:false // System.out.println(str5.equals("abc")); // 不推荐:报错,空指针异常NullPointerException System.out.println("================="); String strA = "Java"; String strB = "java"; System.out.println(strA.equals(strB)); // false,严格区分大小写 System.out.println(strA.equalsIgnoreCase(strB)); // true,忽略大小写 // 注意,只有英文字母区分大小写,其他都不区分大小写 System.out.println("abc一123".equalsIgnoreCase("abc壹123")); // false } }
获取功能的方法
- public int length () :返回此字符串的长度。
- public String concat (String str) :将指定的字符串连接到该字符串的末尾。
- public char charAt (int index) :返回指定索引处的 char值。
- public int indexOf (String str) :返回指定子字符串第一次出现在该字符串内的索引。
package demo02; /* String当中与获取相关的常用方法有: public int length():获取字符串当中含有的字符个数,拿到字符串长度。 public String concat(String str):将当前字符串和参数字符串拼接成为返回值新的字符串。 public char charAt(int index):获取指定索引位置的单个字符。(索引从0开始。) public int indexOf(String str):查找参数字符串在本字符串当中首次出现的索引位置,如果没有返回-1值。 */ public class Demo02StringGet { public static void main(String[] args) { // 获取字符串的长度 int length = "asdasfeutrvauevbueyvb".length(); System.out.println("字符串的长度是:" + length); // 拼接字符串 String str1 = "Hello"; String str2 = "World"; String str3 = str1.concat(str2); System.out.println(str1); // Hello,原封不动 System.out.println(str2); // World,原封不动 System.out.println(str3); // HelloWorld,新的字符串 System.out.println("=============="); // 获取指定索引位置的单个字符 char ch = "Hello".charAt(1); System.out.println("在1号索引位置的字符是:" + ch); System.out.println("=============="); // 查找参数字符串在本来字符串当中出现的第一次索引位置 // 如果根本没有,返回-1值 String original = "HelloWorldHelloWorld"; int index = original.indexOf("llo"); System.out.println("第一次索引值是:" + index); // 2 System.out.println("HelloWorld".indexOf("abc")); // -1 } }
- public String substring (int beginIndex) :返回一个子字符串,从beginIndex开始截取字符串到字符串结尾。
- public String substring (int beginIndex, int endIndex) :返回一个子字符串,从beginIndex到endIndex截取字符串。含beginIndex,不含endIndex。
package demo02; /* 字符串的截取方法: public String substring(int index):截取从参数位置一直到字符串末尾,返回新字符串。 public String substring(int begin, int end):截取从begin开始,一直到end结束,中间的字符串。 备注:[begin,end),包含左边,不包含右边。 */ public class Demo03Substring { public static void main(String[] args) { String str1 = "HelloWorld"; String str2 = str1.substring(5); System.out.println(str1); // HelloWorld,原封不动 System.out.println(str2); // World,新字符串 System.out.println("================"); String str3 = str1.substring(4, 7); System.out.println(str3); // oWo System.out.println("================"); // 下面这种写法,字符串的内容仍然是没有改变的 // 下面有两个字符串:"Hello","Java" // strA当中保存的是地址值。 // 本来地址值是Hello的0x666, // 后来地址值变成了Java的0x999 String strA = "Hello"; System.out.println(strA); // Hello strA = "Java"; System.out.println(strA); // Java } }
转换功能的方法
- public char[] toCharArray () :将此字符串转换为新的字符数组。
- public byte[] getBytes () :使用平台的默认字符集将该 String编码转换为新的字节数组。
- public String replace (CharSequence target, CharSequence replacement) :将与target匹配的字符串使用replacement字符串替换。
package demo02; /* String当中与转换相关的常用方法有: public char[] toCharArray():将当前字符串拆分成为字符数组作为返回值。 public byte[] getBytes():获得当前字符串底层的字节数组。 public String replace(CharSequence oldString, CharSequence newString): 将所有出现的老字符串替换成为新的字符串,返回替换之后的结果新字符串。 备注:CharSequence意思就是说可以接受字符串类型。 */ public class Demo04StringConvert { public static void main(String[] args) { // 转换成为字符数组 char[] chars = "Hello".toCharArray(); System.out.println(chars[0]); // H System.out.println(chars.length); // 5 System.out.println("=============="); // 转换成为字节数组 byte[] bytes = "abc".getBytes(); for (int i = 0; i < bytes.length; i++) { System.out.println(bytes[i]); } System.out.println("=============="); // 字符串的内容替换 String str1 = "How do you do?"; String str2 = str1.replace("o", "*"); System.out.println(str1); // How do you do? System.out.println(str2); // H*w d* y*u d*? System.out.println("=============="); String lang1 = "会不会玩儿呀!你大爷的!你大爷的!你大爷的!!!"; String lang2 = lang1.replace("你大爷的", "****"); System.out.println(lang2); // 会不会玩儿呀!****!****!****!!! } }
分割功能的方法
- public String[] split(String regex) :将此字符串按照给定的regex(规则)拆分为字符串数组。
package demo02; /* 分割字符串的方法: public String[] split(String regex):按照参数的规则,将字符串切分成为若干部分。 注意事项: split方法的参数其实是一个“正则表达式” 今天要注意:如果按照英文句点“.”进行切分,必须写"\."(两个反斜杠) */ public class Demo05StringSplit { public static void main(String[] args) { String str1 = "aaa,bbb,ccc"; String[] array1 = str1.split(","); for (int i = 0; i < array1.length; i++) { System.out.println(array1[i]); } System.out.println("==============="); String str2 = "aaa bbb ccc"; String[] array2 = str2.split(" "); for (int i = 0; i < array2.length; i++) { System.out.println(array2[i]); } System.out.println("==============="); String str3 = "XXX.YYY.ZZZ"; String[] array3 = str3.split("\."); System.out.println(array3.length); // 0 for (int i = 0; i < array3.length; i++) { System.out.println(array3[i]); } } }
String与其他数据类型转换
字符数组 ----> 字符串
- String 类的构造器:String(char[]) 和 String(char[],int offset,int length) 分别用字符数组中的全部字符和部分字符创建字符串对象。
字符串 ------> 字符数组
- public char[] toCharArray():将字符串中的全部字符存放在一个字符数组 中的方法。
- public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin):提供了将指定索引范围内的字符串存放到数组中的方法。
字节数组 -----> 字符串
- String(byte[]):通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。
- String(byte[],int offset,int length) :用指定的字节数组的一部分, 即从数组起始位置offset开始取length个字节构造一个字符串对象。
字符串 ------> 字节数组
- public byte[] getBytes() :使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
- public byte[] getBytes(String charsetName) :使用指定的字符集将 此 String 编码到 byte 序列,并将结果存储到新的 byte 数组。
package demo01; import org.junit.Test; import java.io.UnsupportedEncodingException; import java.util.Arrays; /** * 涉及到String类与其他结构之间的转换 * * @author shkstart * @create 2019 下午 2:39 */ public class StringTest1 { /* String 与 byte[]之间的转换 编码:String --> byte[]:调用String的getBytes() 解码:byte[] --> String:调用String的构造器 编码:字符串 -->字节 (看得懂 --->看不懂的二进制数据) 解码:编码的逆过程,字节 --> 字符串 (看不懂的二进制数据 ---> 看得懂) 说明:解码时,要求解码使用的字符集必须与编码时使用的字符集一致,否则会出现乱码。 */ @Test public void test3() throws UnsupportedEncodingException { String str1 = "abc123中国"; byte[] bytes = str1.getBytes();//使用默认的字符集,进行编码。 System.out.println(Arrays.toString(bytes)); byte[] gbks = str1.getBytes("gbk");//使用gbk字符集进行编码。 System.out.println(Arrays.toString(gbks)); System.out.println("******************"); 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);//没有出现乱码。原因:编码集和解码集一致! } /* String 与 char[]之间的转换 String --> char[]:调用String的toCharArray() char[] --> String:调用String的构造器 */ @Test public void test2(){ String str1 = "abc123"; //题目: a21cb3 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 与基本数据类型、包装类之间的转换。 String --> 基本数据类型、包装类:调用包装类的静态方法:parseXxx(str) 基本数据类型、包装类 --> String:调用String重载的valueOf(xxx) */ @Test public void test1(){ String str1 = "123"; // int num = (int)str1;//错误的 int num = Integer.parseInt(str1); String str2 = String.valueOf(num);//"123" String str3 = num + ""; System.out.println(str1 == str3); } }
键盘输入一个字符串,并且统计其中各种字符出现的次数。种类有:大写字母、小写字母、数字、其他
package demo02; import java.util.Scanner; /* 思路: 1. 既然用到键盘输入,肯定是Scanner 2. 键盘输入的是字符串,那么:String str = sc.next(); 3. 定义四个变量,分别代表四种字符各自的出现次数。 4. 需要对字符串一个字、一个字检查,String-->char[],方法就是toCharArray() 5. 遍历char[]字符数组,对当前字符的种类进行判断,并且用四个变量进行++动作。 6. 打印输出四个变量,分别代表四种字符出现次数。 */ public class Demo07StringCount { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入一个字符串:"); String input = sc.next(); // 获取键盘输入的一个字符串 int countUpper = 0; // 大写字母 int countLower = 0; // 小写字母 int countNumber = 0; // 数字 int countOther = 0; // 其他字符 char[] charArray = input.toCharArray(); for (int i = 0; i < charArray.length; i++) { char ch = charArray[i]; // 当前单个字符 if ('A' <= ch && ch <= 'Z') { countUpper++; } else if ('a' <= ch && ch <= 'z') { countLower++; } else if ('0' <= ch && ch <= '9') { countNumber++; } else { countOther++; } } System.out.println("大写字母有:" + countUpper); System.out.println("小写字母有:" + countLower); System.out.println("数字有:" + countNumber); System.out.println("其他字符有:" + countOther); } }
StringBuffer类
概述:java.lang.StringBuffer代表可变的字符序列,JDK1.0中声明,可以对字符 串内容进行增删,此时不会产生新的对象。很多方法与String相同。作为参数传递时,方法内部可以改变值。StringBuffer和StringBuilder的方法基本上都一样。唯一的区别就是效率问题。
StringBuilder类丶String类丶StringBuffer的区别
常用的构造方法
StringBuffer类不同于String,其对象必须使用构造器生成。有三个构造器:
- StringBuffer():初始容量为16的字符串缓冲区
- StringBuffer(int size):构造指定容量的字符串缓冲区
- StringBuffer(String str):将内容初始化为指定字符串内容
常用方法
- StringBuffer append(xxx):提供了很多的append()方法,用于进行字符串拼接
- StringBuffer delete(int start,int end):删除指定位置的内容
- StringBuffer replace(int start, int end, String str):把[start,end)位置替换为str
- StringBuffer insert(int offset, xxx):在指定位置插入xxx
- StringBuffer reverse() :把当前字符序列逆转
代码演示
public class StringBuilderDemo { public static void main(String[] args) { //创建对象 StringBuilder sb = new StringBuilder(); //public StringBuilder append(任意类型):添加数据,并返回对象本身 //链式编程 sb.append("hello").append("world").append("java").append(100); System.out.println("sb:" + sb); //public StringBuilder reverse():返回相反的字符序列 sb.reverse(); System.out.println("sb:" + sb); } }
StringBuilder和String相互转换
- StringBuilder转换为String :public String toString():通过 toString() 就可以实现把 StringBuilder 转换为 String
- String转换为StringBuilder:public StringBuilder(String s):通过构造方法就可以实现把 String 转换为 StringBuilder