• Java中的String数据类型,String类(字符串)详解


    第一章、String概述

    1)String是什么

    ①String表示字符串类型,是引用数据类型不是基本数据类型,String是类且是最终类,不能有子类。
    ②字符串虽然是引用类型属于对象,但是它不是存储在堆空间中,而是存储在方法区中的字符串常量池中。只要我们书写了双引号,数据都会立刻在字符串常量池中保存。
    在这里插入图片描述

    2)String长什么样

    使用双引号包裹起来的都是String。
    ①一个字母被双引号包裹起来的:

    A
    • 1

    ②多个字母被双引号包裹起来的:

    “hello daShaGua!
    • 1

    ③中文被双引号包裹起来的:

    “你好小可爱”
    
    • 1

    3)String的构造方法(声明方式)

    字符串常用的构造方法:6种

    构造方法作用
    String()初始化一个新创建的 String 对象,使其表示一个空字符序列。
    String(String original)初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。
    String(byte[] bytes)通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。
    String(byte[] bytes, int offset, int length)通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。
    String(char[] value)分配一个新的 String,使其表示字符数组参数中当前包含的字符序列。
    String(char[] value, int offset, int count)分配一个新的 String,它包含取自字符数组参数一个子数组的字符。
    Column 1Column 2
    centered 文本居中right-aligned 文本居右
    	public static void test1(){
    	//String()|  初始化一个新创建的 String 对象,使其表示一个空字符序列。
    		String s1 = "";					//空字符串
    		String s2 = new String();		//空字符串
    		
    	//String(String original)| 初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;
    		String s3 = new String("");		//空字符串
    		String s4 = new String("qwer");
    		
    	//String(byte[] bytes)  |通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。	
    		byte[] bs = {65,66,97,98};
    		//类型转换:byte[] --> String
    		String str = new String(bs);
    		System.out.println(str);	//"ABab"
    		
    	//String(byte[] bytes, int offset, int length)   
    	//通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。	
    		byte[] bs3 = {65,66,67,68,97,98,99,100};
    		//类型转换:byte[] --> String
    		String str3 = new String(bs3, 2, 5);
    		System.out.println(str3);	//"CDab"
    
    	//String(char[] value)  | 初始化一个新创建的 String 对象,使其表示字符数组参数中当前包含的字符序列。
    		char[] cs = {'j','a','v','a'};
    		//类型转换:char[] --> String
    		String str = new String(cs);
    		System.out.println(str);		//"java"
    		
    	//String(char[] value, int offset, int count)  | 包含取自字符数组参数一个子数组的字符。	
    		String str1 = new String(cs,0,2);
    		System.out.println(str1);		//"ja"
    		
    	}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    第二章、String类的详解

    1)String底层是什么

    查看源码可以发现,String的底层是数组。
    jdk1.8及以前String使用的是char数组
    在这里插入图片描述

    jdk1.9及以后使用的是byte数组
    在这里插入图片描述
    因为字符串底层是数组,所以可以遍历字符串

    		//第一种方式
    		//char charAt(int index):返回指定索引处的 char 值。 
    		String str = "java";
    		
    		for(int i = 0;i <= str.length() - 1;i++){
    			char c = str.charAt(i);
    			System.out.print(c);
    		}
    //---------------------------分割------------------------------------------
    		//第二种方式
    		 //	char[] toCharArray():将此字符串转换为一个新的字符数组。 
    		char[] cs = str.toCharArray();
    		for(int i = 0;i <= cs.length - 1;i++){
    			System.out.print(cs[i]);
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2)字符串存储的内存原理/字符串常量池(String Constant Pool)

    ①字符串被保存在字符串常量池中,在JDK1.8 字符串常量池在堆中, 运行时常量池在方法区。
    ②在java中String类型的值是不可改变的,指的是想要改变字符串值时会复用字符串常量池中的地址值。
    例如:我们有一个字符串变量s = “a”,然后我们再对s赋值为”b”,我们并没有改变字符串s的值,只是在常量池中新建了一个字符串”b”,然后让s的地址值从指向”a”变成了指向”b”。

    String s = "a";
    s = "b";//并没有改变S的值,只是在常量池中新建了一个字符串”b”,然后让s从指向”a”变成了指向”b”
    
    • 1
    • 2

    ③直接赋值会复用字符串常量池中的地址值,new出来的不会复用,而是开辟一个新的空间

    //直接赋值会复用字符串常量池中的地址
    //它们的地址是一样的,这个就是 String 的复用性。"abc"在常量池中的,并且 s1 和 s2 都指向同一个地方。
    		String s1 = "abc";
    		String s2 = "abc";
    		System.out.println(s1 == s2);		//true 比较的是地址值,s1和s2在常量池理指向了同一个地址值
    		
    		System.out.println(s1.equals(s2));	//true 底层重写了toString所以调用equals方法时比较的是内容
    //new出来的不会复用,而是开辟一个新的空间		
    		String s3 = new String("abc");
    		
    		System.out.println(s1 == s3);			//false new出来的不会复用,而是开辟一个新的空间
    		System.out.println(s1.equals(s3));		//true 底层重写了toString所以调用equals方法时比较的是内容
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    ps:这里放一个老师的考题

    
    			//【问题】:执行完毕下列5行代码,内存中一共有几个对象?
    			//答:4个对象
    		
    		String s1 = "hello";					//1个对象		在常量池中
    		String s2 = "hello";					//不会产生对象
    		String s3 = new String("hello");		//1个对象		在堆中
    		String s4 = new String("helloworld");	//2个对象		一个在堆中,另一个在常量池中
    		String s5 = "helloworld";				//不会产生对象
    		//所以一共是四个对象
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3)字符串之间的比较问题

    ①字符串之间的直接比较

    1、==比较的是地址值
    2、equals比较的是字符串内容

    //直接赋值会复用字符串常量池中的地址
    //它们的地址是一样的,这个就是 String 的复用性。"abc"在常量池中的,并且 s1 和 s2 都指向同一个地方。
    		String s1 = "abc";
    		String s2 = "abc";
    		System.out.println(s1 == s2);		//true 比较的是地址值,s1和s2在常量池理指向了同一个地址值
    		
    		System.out.println(s1.equals(s2));	//true 底层重写了toString所以调用equals方法时比较的是内容
    //new出来的不会复用,而是开辟一个新的空间		
    		String s3 = new String("abc");
    		
    		System.out.println(s1 == s3);			//false new出来的不会复用,而是开辟一个新的空间
    		System.out.println(s1.equals(s3));		//true 底层重写了toString所以调用equals方法时比较的是内容
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    ②字符串拼接完毕后做==比较的问题

    1、字符串内容做==比较,比较的是地址值,
    2、常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量,只要其中有一个是变量,结果就在堆中
    3、只有常量池中数据内容进行,比较结果才会为true,有堆参与结果一定为false
    4、如果拼接的结果调用intern()方法,返回值就在常量池中

    		String s1 = "hello";			//s1变量记录的是"hello"常量数据在常量池中的地址
    		String s2 = "world";			//s2变量记录的是"world"常量数据在常量池中的地址
    		String s3 = "helloworld";		//s3变量记录的是"helloworld"常量数据在常量池中的地址
    		
    		System.out.println("hello" + s2 == s3);			//常量 + 变量 	结果在堆中     堆 == 常量池		false
    		System.out.println(s1 + "world" == s3);			//变量 + 常量 	结果在堆中	   堆 == 常量池		false
    		System.out.println(s1 + s2 == s3);				//变量 + 变量 	结果在堆中	   堆 == 常量池		false
    		System.out.println("hello" + "world" == s3);	//常量 + 常量 	结果在常量池中 常量池 == 常量池	true
    		
    		System.out.println("================================");
    		
    		System.out.println("hello" + s2 == "hello" + s2);				//堆 == 堆			false
    		System.out.println(s1 + "world" == s1 + "world");				//堆 == 堆			false
    		System.out.println(s1 + s2 == s1 + s2);							//堆 == 堆			false
    		System.out.println("hello" + "world" == "hello" + "world");		//常量池 == 常量池		true
    		
    		System.out.println("*********************************");
    		
    		/*
    		 * 	String intern():返回字符串对象的规范化表示形式。 
    		 * 	分析:
    		 * 		jvm会去常量池中查找是否存在该字符串常量对象:
    		 * 		如果存在,则直接返回该常量对象在常量池中的地址信息
    		 * 		如果不存在,则先在常量池中创建该常量对象,再返回其在常量池中的地址信息
    		 */
    		System.out.println(("hello" + s2).intern() == ("hello" + s2).intern());					//常量池 == 常量池		true
    		System.out.println((s1 + "world").intern() == (s1 + "world").intern());					//常量池 == 常量池		true
    		System.out.println((s1 + s2).intern() == (s1 + s2).intern());							//常量池 == 常量池		true
    		System.out.println(("hello" + "world").intern() == ("hello" + "world").intern());		//常量池 == 常量池		true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    4)字符串与其他类型的转换

    ①String字符串与基本数据类型的转换

    1、字符串转为基本类型

    String s1 = "123";
    		int i = Integer.parseInt(s1);
    		//类型转换:字符串转为基本类型
    		String s2 = "3.14";
    		double d = Double.parseDouble(s2);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2、基本类型转为字符串

    int num = 123;
    		//类型转换:基本类型 -> String
    		String s1 = num + "";
    		String s2 = Integer.toString(num);
    		String s3 = String.valueOf(num);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ②String字符串与包装类型的转换

    1、包装类型转为字符串

    Integer iObj = Integer.valueOf(123);
    		//类型转换:包装类型 -> 字符串类型
    		String str = iObj.toString();
    		System.out.println(str);						//"123"
    		System.out.println(str instanceof String);		//true
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2、字符串转为包装类型

    //类型转换:String -> 包装类型
    			Integer iObj1 = new Integer("123");
    			Double dObj = Double.valueOf("3.14");
    
    • 1
    • 2
    • 3

    5)String类常用方法

    String类常用方法:将字符串内容转换为全大写/小写

    	public static void test5(){
    		/*
    		 * 	将字符串内容转换为全大写/小写
    			 * 	String toLowerCase():使用默认语言环境的规则将此 String 中的所有字符都转换为小写。 
    			 *  String toUpperCase():使用默认语言环境的规则将此 String 中的所有字符都转换为大写。 
    		 */
    		String content = "Today is Friday pm";
    		String newContent = content.toLowerCase();
    		System.out.println(newContent);// 打印结果 today is friday pm
    
    	
    
    		
    		newContent = content.toUpperCase();
    		System.out.println(newContent);// 打印结果 TODAY IS FRIDAY PM
    		System.out.println(content);// 打印结果 Today is Friday pm
    	}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    String类常用方法:查找字符在字符串中的位置

    	public static void test4(){
    		/*
    		 * 	得到传入的字符串在原串中首次/最后一次出现的位置:
    			 * 	int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引。 
    	 			int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始。 
    				int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引。 
    	 			int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。 
    	 			
    	 		注意:
    	 			从头到尾都比对不上,就返回-1
    		 */
    		String content = "山不在在高,有仙则名。水不在在深,有龙则灵。斯是陋室,惟吾德馨。";
    		int index = content.indexOf("在");//从第0个索引开始找,在第2个索引找到  第一个在
    		System.out.println(index);	//2
    		
    		index = content.indexOf("在", 5); //从第5个索引开始找,在第13个索引找到  第一个在
    		System.out.println(index);	//13
    		
    		index = content.lastIndexOf("则");//从第0个索引开始找,在第19个索引找到  最后一个则
    		System.out.println(index);	//19
    		
    		index = content.lastIndexOf("则",18);//从第18个索引开始向前找,在第8个索引找到  最后一个则
    		System.out.println(index);	//8
    		
    		index = content.indexOf("在在");//从第0个索引开始找,在第2个索引找到  第一个  在在
    		System.out.println(index);	//2
    		
    		index = content.indexOf("在再");//从第0个索引开始找,没找到  在再   返回-1
    		System.out.println(index);		//-1
    	}
    	
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    String类常用方法:根据参数截取字符串,获得新字符串

    
    		/*	截取字符串:
    			String substring(int beginIndex):
    	 		String substring(int beginIndex, int endIndex):
    	 		方法的参数存在起始索引和结束索引,绝大多数情况下,都满足含头不含尾的特点
    		 */
    		String content = "唧唧复唧唧,木兰当户织。不闻机杼声,惟闻女叹息。";
    		
    		String newContent = content.substring(4);
    		System.out.println(content);//打印结果 唧唧复唧唧,木兰当户织。不闻机杼声,惟闻女叹息。
    		System.out.println(newContent);//打印结果 唧,木兰当户织。不闻机杼声,惟闻女叹息。
    
    		newContent = content.substring(3, 5);
    		System.out.println(newContent);//打印结果 唧唧
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    String类常用方法:切割字符串,返回数组

    		//根据正则规则切割字符串:String[] split(String regex):根据给定正则表达式的匹配拆分此字符串。 
    		//如果匹配不上,则不做任何的切割行为,将原串作为一个整体存入到数组容器中
    		 
    		String content = "java is a good lang,java is a nice lang";
    		String regex = ",";
    		String[] strs = content.split(regex);
    		System.out.println(Arrays.toString(strs) + "-->" + strs.length);
    		//打印结果[java is a good lang , java is a nice lang]-->3
    	
    		
    		String[] strs2 = content.split("@");
    		System.out.println(Arrays.toString(strs2) + "-->" + strs2.length);
    		//打印结果[java is a good lang , java is a nice lang]-->1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    String类常用方法:拼接字符串的两种方式

    	//第一种
    	//拼接字符串:String concat(String str):将指定字符串连接到此字符串的结尾。 
    	
    		String s1 = "遥想公瑾当年,";
    		String s2 = "小乔初嫁了。";
    		String result = s1.concat(s2);
    		System.out.println(result);
    	//第二种	
    		System.out.println("谈笑间," + "樯橹灰飞烟灭");
    	
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    第三章、字符串缓冲区StringBuffer和StringBuilder

    1)字符串缓冲区概述

    ①String是不能更改的,而StringBuffer与StringBuilder则是可变的字符序列。可以看成是高级的String。二者的内部方法是一致的。
    ②缓冲区就是一个临时空间,它里面可以临时存储数据。缓冲区本身就是一个容器,把需要修改的字符串先存储到字符串缓冲区容器中,在容器中修改完成后存储在字符串常量池中。
    ③任意类型都可以存储到字符串缓冲区。注意:是将任意数据都转成字符串进行存储;容器对象提供很多对容器中的数据操作的功能,比如添加,删除,修改,查询;
    ④StringBuffer它的线程安全是通过把各种修改数据的方法都加上 synchronized 关键字实现的,StringBuilder 是 Java 1.5 中新增的,它是在单线程环境下使用的所以去
    掉了线程安全的部分所有方法都没有被 synchronized 修饰,相较于 StringBuffer 有速度优势。

    2)StringBuffer和StringBuilder声明方式

    // 默认含有16个字符的容量
    StringBuffer sb1 = new StringBuffer();
    //含12个字符容量的字符串缓冲区
    StringBuffer sb2 = new StringBuffer(12);
    // 含16+4的字符串缓冲区,"b cd"为4个字符容量
    StringBuffer sb3 = new StringBuffer("b cd");
    
    //StringBuilder 同理,就不一一举例了
    StringBuilder sb = new StringBuilder("");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3)StringBuffer/StringBuilder和String类型之间的转换

    //String类型--》StringBuilder
    StringBuilder builder = new StringBuilder("abc");
    StringBuilder builder2 = new StringBuilder("abcde");
    
    StringBuilder类型--》String
    String str = builder.toString();
    String str2= new String(builder2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4)二者的常用方法

    ①添加

     //空参构造
            StringBuilder sb = new StringBuilder();
             // 增操作:append和insert
            //尾部追加数据append
            sb.append("abc").append(123).append(3.14).append(true);
            System.out.println(sb);     //缓冲区对象内部数据为 ==> "abc1233.14true"
    
     //带参构造
            StringBuilder sb2 = new StringBuilder("helloworld");
            System.out.println(sb2);//打印结果 helloworld
    
    
            //在中间某位置插入数据 insert
            sb2.insert(5, "java");
            System.out.println(sb2); //打印结果 hellojavaworld
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    ②删除

    		StringBuilder sb = new StringBuilder("helloabc0world");
              //  删操作:delete    deleteCharAt
              
            //删除中间的"abc"数据
            sb.delete(5, 8);
            System.out.println(sb);//打印结果 hello0world
            
            //删除中间的'0'数据
    		sb.deleteCharAt(5);
            System.out.println(sb);//打印结果 helloworld
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    ③修改

      /*
          改操作:reverse
           		 setCharAt
                 setLength  */
                 
            String content = "上海自来水来自海上1";
            //类型转换:String -> StringBuilder
            StringBuilder sb = new StringBuilder(content);
            //将sb中的字符串内容进行反转
            sb.reverse();
    //-------------------------------分割--------------------------------
            StringBuilder sb2 = new StringBuilder("helloworldjavascript");
    		
            //将sb2对象的容量设置为10个长度==》setLength方法
            sb2.setLength(10);
            System.out.println(sb2);        //打印结果 "helloworld"
    
            //将字符串内容w 改为W==》setCharAt方法
            sb2.setCharAt(5, 'W');
            System.out.println(sb2);//打印结果 helloWorld
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
  • 相关阅读:
    【Qt炫酷动画】7.浅谈动画设计的一些思考
    Java中生成一个唯一的文件名的方法
    Java的日期与时间之java.time.LocalDateTime简介说明
    22杭电多校11 Find different(环计数问题)
    GBASE 8S内存管理
    HTML5 用FileReader对象读取图片
    web监听器解析
    震惊,一个csdn小编用Python语言写了一个足球游戏,成功模拟世界杯决赛现场
    nn.Linear(d, num_units, bias=True)设置bias和不设置bias有什么区别?
    MYSQL介绍——数据库的增删改及常用函数
  • 原文地址:https://blog.csdn.net/baomingshu/article/details/130855286