JAVA | 聚焦 String 的常见用法与底层内存原理

打印 上一主题 下一主题

主题 936|帖子 936|积分 2808

*个人主页

文章专栏

《赛博算命之梅花易数的JAVA实现》*



  
#前言:API

1.定义

API(Application Programming Interface)应用程序编程接口
简单理解:API就是别人已经写好的东西,我们不必要自己编写,直接使用即可
  1. public static void main (String []args){
  2.     Random r = new Random ();
  3.     int number = r.nextInt (100);
  4. }
复制代码
Java API : 指的就是JDK提供的各种功能的Java类
这些类将底层的实现封装了起来,我们不必要关心这些类是如何实现的,只必要学习这些类如何使用即可。
2.已经学习过的API

Scanner 键盘录入
Random 随机数
API和API帮助文档
API:目前是JDK中提供的各种功能的Java类
这些类将底层的实现封装了起来,我们不必要关心这些类是如何实现的,只必要学习这些类如何使用即可。
API帮助文档:帮助开辟职员更好的使用API和查询API的一个工具
3.如何使用帮助文档:



  • 打开API帮助文档
  • 点击显示,并找到索引下面的输入框、
  • 在输入框中输入类名并点击显示
  • 检察类所在的包
  • 检察类的描述(一样平常环境下,只必要看第一行)
  • 检察构造方法
  • 查当作员方法
一、String

1、String概述

java.lang.String类代表字符串,java程序中的全部字符串文字(例如:”abc“)都为此类的对象。
String 是java定义好的一个类。定义在java.lang包中,所以使用的时候不必要导包。
  1. String name = "尼古拉斯";
  2. String schoolName = "黑马程序员";
复制代码
2.String的注意点

字符串的内容是不会发生改变的,它的对象在创建后不能被更改
  1. String name = "爱因斯晨";
  2. String schoolName = "黑马程序员";
  3. System.out.println(name+schoolName);
复制代码
3.创建String对象的两种方式


  • 直接赋值
    1. String name = "爱因斯晨";
    复制代码
  • new
       构造方法阐明public String ()创建空缺字符串,不含任何内容public String (String original )根据传入的字符串,创建字符串对象public String(char [] chs)根据字符数组,创建字符串对象public String (byte [] chs)根据字节数组,创建字符串对象
    1. public class zifuu {
    2.     public static void main(String[] args) {
    3.         //直接赋值
    4.         String s1 = "abc";
    5.         System.out.println(s1);
    6.         //使用new的方式创建字符串
    7.         //空参构造
    8.         String s2 = new String();
    9.         System.out.println("@"+s2+"#");
    10.         //传递一个字符串,根据传递的字符串内容再创建一个新的字符串对象
    11.         String s3 = new String(original:"abc");
    12.         System.out.println(s3);
    13.         //传递一个字符数组,根据字符数组的内容,再创建一个新的字符串对象
    14.         char[] ch = {'a','b','c'};
    15.         String s4 = new String(ch);
    16.         System.out.println(s4);
    17.         
    18.         //传递一个字节数组,根据字节数组的内容再创建一个新的字符串对象。
    19.         byte [] bytes ={97,98,99};
    20.         String s5 = new String (bytes);
    21.         System.out.println(s5);
    22.     }
    23. }
    复制代码
3.区别与用法:
Java的内存模子



注意:StringTable(串池)在JDK7版本开始,从方法区中挪到了堆内存
举例1:
  1. public class Zicun {
  2.     public static void main(String[] args) {
  3.         String s1 = "abc";
  4.         String s2 = "abc";
  5.         System.out.println(s1);
  6.         System.out.println(s2);
  7.     }
  8. }
复制代码

当使用双引号直接赋值的时候,系统会查抄该字符串在串池中是否存在。
不存在:创建新的
存在:复用
举例2:
  1. public class fif {
  2.     public static void main(String[] args) {
  3.         char[] ch = {'a','b','c'};
  4.         String str = new String(ch);
  5.         String str1 = new String(ch);
  6.     }
  7. }
复制代码

地址值不会复用
综上所述:我们保举使用直接赋值,不仅由于书写简单而且内存方便
4.java的常用方法(比较)

  1. public class bijiao {
  2.     public static void main(String[] args) {
  3.         String str1 = "abc";//串池里面有地址
  4.         String str2 = "abc";//复用串池里面的地址
  5.         System.out.println(str1==str2);
  6.     }
  7. }
  8. //run:true
复制代码
  1. public class bijiao {
  2.     public static void main(String[] args) {
  3.         String str1 = "aaa";
  4.         String str2 = "bbb";
  5.         System.out.println(str1==str2);
  6.     }
  7. }
  8. //run:false
复制代码
  1. public class bijiao {
  2.     public static void main(String[] args) {
  3.         String str1 = new String("abc");//记录的是堆里面的地址
  4.         String str2 = "abc";//记录的是串池里面的地址
  5.         System.out.println(str1==str2);
  6.     }
  7. }
  8. //run:false
复制代码
==号比的到底是什么?

  • 基本数据范例:比较的是数据值
    1. int a = 10;
    2. int b = 20;
    3. System.out.println(a==b);//false
    复制代码
  • 引用数据范例:比较的是地址值
    1. String s1 = new String ("abc");
    2. String s2 = new String ("abc");
    3. System.out.println(s1==s2);//false
    复制代码
字符串比较的方法:

  1. boolean equals 方法(要比较的字符串)
  2. 完全一样结果才是true,否则为false
  3. boolean equalslgnoreCase(要比较的字符串)
  4. 忽略大小写的比较
复制代码
  1. public class Stringd {
  2.     public static void main(String[] args) {
  3.         //1.创建两个字符串对象
  4.         String s1 = new String("abc");
  5.         String s2 = "ABC";
  6.         //2.==号比较
  7.         //基本数据类型:比较的是数据值是否相同
  8.         //引用数据类型:比较的是地址值是否相同
  9.         System.out.println(s1 == s2);
  10.         //3.比较字符串内容是否相同
  11.         boolean result =s1.equals(s2);
  12.         System.out.println(result);
  13.         //4.忽略大小写比较字符串内容是否相同
  14.         //忽略大小写只能是英文
  15.         boolean result2 = s1.equalsIgnoreCase(s2);
  16.         System.out.println(result2);
  17.     }
  18. }
  19. //run:
  20. //false
  21. //false
  22. //true
复制代码
  1. //键盘录入:
  2. import java.util.Scanner;
  3. public class llu {
  4.     public static void main(String[] args) {
  5.         //1.假设键盘录入一个abc
  6.         Scanner sc = new Scanner(System.in);
  7.         System.out.println("请输入一个字符串:");
  8.         String s = sc.next();
  9.         //2.代码中再定义一个字符串abc
  10.         String s2 = "abc";
  11.         //3.比较两个字符串内容是否相同
  12.         boolean result = s.equals(s2);
  13.         System.out.println(result);
  14.     }
  15. }
复制代码
训练:
  1. //练习:已知正确的用户名和密码,请用程序实现模拟用户登录。总共给三次机会,登录之后,给出相应的提示。
  2. import java.util.Scanner;
  3. public class yanzheng {
  4.     public static void main(String[] args) {
  5.         //定义正确的用户名和密码
  6.         String rightUserName = "aiyinsichen";
  7.         String rightPassword = "123456";
  8.         Scanner sc = new Scanner(System.in);
  9.         //模拟用户输入名字与密码,键盘录入
  10.         for (int i = 1; i <= 3; i++) {
  11.             System.out.println("请输入用户名:");
  12.             String userName = sc.next();
  13.             System.out.println("请输入密码:");
  14.             String password = sc.next();
  15.             //比较用户名和密码
  16.             if (rightUserName.equals(userName) && rightPassword.equals(password)) {
  17.                 System.out.println("登录成功");
  18.                 break;
  19.             }else {
  20.                 System.out.println("密码或用户名错误,登录失败,请重新输入");
  21.             }
  22.         }
  23.     }
  24. }
复制代码
遍历字符串

需求:键盘录入一个字符串,使用程序实现在控制台遍历该字符串
  1. public char charAt(int index):根据索引返回字符
  2. public int length():返回此字符串的长度
复制代码
  1. //遍历字符串
  2. import java.util.Scanner;
  3. public class luru {
  4.     public static void main(String[] args) {
  5.        Scanner sc = new Scanner(System.in);
  6.        System.out.println("请输入一个字符串:");
  7.        String a = sc.nextLine();
  8.        //a.length().fori 回车
  9.        for (int i = 0; i < a.length(); i++) {
  10.             //i依次表示字符串的每一个索引
  11.            char c = a.charAt(i);
  12.            System.out.println(c);
  13.         }
  14.     }
  15. }
复制代码
  1. //键盘录入一个字符串,统计该字符串中大写字母字符,小写字母字符,数字字符出现的次数
  2. import java.util.Scanner;
  3. public class shai {
  4.     public static void main(String[] args) {
  5.         //键盘录入一个字符串
  6.         Scanner sc = new Scanner(System.in);
  7.         System.out.println("请输入一个字符串:");
  8.         String str = sc.next();
  9.         //定义三个统计变量,初始值都为0
  10.         int bigCount = 0;
  11.         int smallCount = 0;
  12.         int numberCount = 0;
  13.         for (int i = 0; i < str.length(); i++) {
  14.             char c = str.charAt(i);
  15.             if (c >= 'A' && c <= 'Z') {
  16.                 //char类型的变量在参与计算的时候自动类型提升为int 查询ascii码表
  17.                 bigCount++;
  18.             } else if (c >= 'a' && c <= 'z') {
  19.                 smallCount++;
  20.             } else if (c >= '0' && c <= '9') {
  21.                 numberCount++;
  22.             }
  23.         }
  24.         System.out.println("大写字母字符:" + bigCount);
  25.         System.out.println("小写字母字符:" + smallCount);
  26.         System.out.println("数字字符:" + numberCount);
  27.     }
  28. }
复制代码
拼接字符串

  1. //拼接
  2. //定义一个方法,把int数组中的数据按照指定的格式拼接成一个字符串返回,调用该方法,并在控制台输出结果。
  3. //例如,数组为int[] arr = {1,2,3}; ,执行方法后的输出结果为:[1, 2, 3]
  4. public class pinjie {
  5.     public static void main(String[] args) {
  6.         int[] arr = {1,2,3};
  7.         String s = arrayToString(arr);
  8.         System.out.println(s);
  9.     }
  10.     public static String arrayToString(int[] arr){
  11.         if (arr == null){
  12.             return "";
  13.         }
  14.         if (arr.length == 0){
  15.             return "[]";
  16.         }
  17.         String s = "[";
  18.         for (int i = 0; i < arr.length; i++) {
  19.             if (i == arr.length - 1){
  20.                 s = s + arr[i];
  21.             }
  22.             else{
  23.                 s = s + arr[i] + ",";
  24.             }
  25.         }
  26.         s = s + "]";
  27.         return s;
  28.     }
  29. }
复制代码
反转字符串

  1. //定义一个方法,实现字符串反转
  2. //键盘录入一个字符串,调用该方法,并在控制台输出结果
  3. import java.util.Scanner;
  4. public class fanZhuan {
  5.     public static void main(String[] args) {
  6.         Scanner sc = new Scanner(System.in);
  7.         System.out.println("请输入一个字符串:");
  8.         String s = sc.next();
  9.         //调用方法
  10.         String s1 = fan(s);
  11.         System.out.println("反转后的字符串为:"+s1);
  12.     }
  13.     public static String fan(String s){
  14.         // 将字符串转换为字符数组便于修改
  15.         char[] arr = s.toCharArray();
  16.         // 修正循环初始化和边界条件
  17.         for (int i = 0, j = arr.length - 1; i < j; i++, j--) {
  18.             char temp = arr[i];
  19.             arr[i] = arr[j];
  20.             arr[j] = temp;
  21.         }
  22.         return new String(arr);
  23.     }
  24. }
复制代码
  1. 方法二:
  2. 使用自带的反向遍历的方法:
  3. 变量名.length().forr 回车
  4. import java.util.Scanner;
  5. public class fanzhuan {  // 字符串反转工具类
  6.     public static void main(String[] args) {
  7.         Scanner sc = new Scanner(System.in);  
  8.         // 创建控制台输入扫描器
  9.         String n = sc.next();               
  10.         // 读取用户输入的字符串
  11.         String result = fan(n);              
  12.         // 调用反转方法处理输入
  13.         System.out.println(result);           
  14.         // 输出反转结果
  15.     }
  16.     // 字符串反转核心方法
  17.     public static String fan(String s) {   
  18.         // 参数s: 原始字符串
  19.         String s1 = "";
  20.         //s.length().forr回车,就是反向遍历(保留用户原有注释)
  21.         for (int i = s.length()-1; i >= 0; i--) {
  22.             // 倒序循环:从末位到首位
  23.             char c = s.charAt(i);            
  24.             // 提取当前位置字符
  25.             s1 = s1 + c;                     
  26.             // 反向拼接字符
  27.         }
  28.         return s1;                          
  29.         // 返回反转后的结果
  30.     }
  31. }
复制代码
综合训练:
  1. 金额转换:如键盘录入234.输出大写方法
  2. import java.util.Scanner;
  3. /**
  4. * Demoutwo 类用于将用户输入的金额转换为中文大写金额表示。
  5. */
  6. public class Demoutwo {
  7.     /**
  8.      * 程序的入口点,处理用户输入的金额并将其转换为中文大写金额。
  9.      *
  10.      * @param args 命令行参数,在本程序中未使用。
  11.      */
  12.     public static void main(String[] args) {
  13.         // 1. 键盘录入一个金额
  14.         // 创建一个 Scanner 对象,用于从标准输入读取用户输入
  15.         Scanner sc = new Scanner(System.in);
  16.         // 定义变量 money 用于存储用户输入的金额
  17.         int money;
  18.         // 使用 while 循环确保用户输入的金额在有效范围内(0 到 9999999 之间)
  19.         while (true) {
  20.             // 提示用户输入一个金额
  21.             System.out.println("请输入一个金额:");
  22.             // 从标准输入读取一个整数作为金额
  23.             money = sc.nextInt();
  24.             // 检查金额是否在有效范围内
  25.             if (money >= 0 && money <= 9999999) {
  26.                 // 如果金额有效,跳出循环
  27.                 break;
  28.             } else {
  29.                 // 如果金额无效,提示用户并继续循环等待新的输入
  30.                 System.out.println("金额无效");
  31.             }
  32.         }
  33.         // 2. 把金额转换为中文
  34.         // 定义一个空字符串 str 用于存储转换后的中文金额
  35.         String str = "";
  36.         // 使用 while 循环将金额逐位转换为中文数字
  37.         while (true) {
  38.             // 获取当前金额的个位数字
  39.             int ge = money % 10;
  40.             // 调用 getChinaNum 方法将个位数字转换为中文数字
  41.             String chinaNum = getChinaNum(ge);
  42.             // 将中文数字拼接到 str 字符串的前面
  43.             str = chinaNum + str;
  44.             // 去掉刚刚处理的个位数字
  45.             money = money / 10;
  46.             // 检查金额是否已经处理完
  47.             if (money == 0) {
  48.                 // 如果金额为 0,跳出循环
  49.                 break;
  50.             }
  51.         }
  52.         // 3. 补零,补到 7 位
  53.         // 计算需要补充的零的数量
  54.         int count = 7 - str.length();
  55.         // 使用 for 循环在 str 字符串前面补充零
  56.         for (int i = 0; i < count; i++) {
  57.             str = "零" + str;
  58.         }
  59.         // 输出补零后的中文数字字符串
  60.         System.out.println(str);
  61.         // 4. 插入单位
  62.         // 定义一个字符串数组 arr2,包含中文金额的单位
  63.         String[] arr2 = {"佰", "拾", "万", "仟", "佰", "拾", "元"};
  64.         // 使用 for 循环遍历补零后的中文数字字符串
  65.         for (int i = 0; i < str.length(); i++) {
  66.             // 获取当前位置的中文数字字符
  67.             char c = str.charAt(i);
  68.             // 将中文数字字符和对应的单位拼接成一个新的字符串
  69.             String s = c + arr2[i];
  70.             // 输出拼接后的字符串
  71.             System.out.print(s);
  72.         }
  73.     }
  74.     /**
  75.      * 将阿拉伯数字转换为中文大写数字。
  76.      *
  77.      * @param number 要转换的阿拉伯数字(0 到 9 之间)
  78.      * @return 对应的中文大写数字字符串
  79.      */
  80.     public static String getChinaNum(int number) {
  81.         // 定义一个字符串数组 arr,包含中文大写数字
  82.         String[] arr = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
  83.         // 返回数组中对应索引的中文大写数字
  84.         return arr[number];
  85.     }
  86. }
复制代码
字符串截取

  1. 截取:
  2. String substring (int beginlandex , int endlndex )
  3. 注意点:包头不包尾,包左不包右
  4.     只有返回值才是截取的小串
  5. String substring (int beginlndex) 截取到末尾
复制代码
  1. //加密电话号码:
  2. //15552534681
  3. //加密成:155****4681
  4. import java.util.Scanner;
  5. public class demout {
  6.     public static void main(String[] args) {
  7.         Scanner sc = new Scanner(System.in);
  8.         System.out.println("请输入你的手机号码");
  9.         String s = sc.nextLine();
  10.         String s1 = s.substring(0,3);
  11.         String s2 = s.substring(7);
  12.         System.out.println(s1+"****"+s2);
  13.     }
  14. }
复制代码
  1. //练习:
  2. //读取身份证中的信息:出生年月日还有性别
  3. import java.util.Scanner;
  4. public class demofour {
  5.     public static void main(String[] args) {
  6.         Scanner sc = new Scanner(System.in);
  7.         System.out.println("请输入你的身份证号码");
  8.         String id = sc.next();
  9.         String year = id.substring(6,10);
  10.         String month = id.substring(10,12);
  11.         String day = id.substring(12,14);
  12.         int xing = id.charAt(16);
  13.         String gender;
  14.         if (xing % 2 == 0) {
  15.            gender = "女";
  16.         }else{
  17.             gender = "男";
  18.         }
  19.         System.out.println("人物信息为:");
  20.         System.out.println("出生年月日为:"+year+"年"+month+"月"+day+"日");
  21.         System.out.println("性别为:"+gender);
  22.     }
  23. }
复制代码
字符串的更换

  1. String replace (旧值,新值)替换
  2. 注意点:只有返回值才是替换之后的结果
复制代码
  1. //练习:敏感词屏蔽
  2. import java.util.Scanner;
  3. public class mingan {
  4.     public static void main(String[] args) {
  5.         Scanner sc = new Scanner(System.in);
  6.         System.out.println("请输入一句话");
  7.         String said = sc.next();
  8.         String [] cyuyan ={"cnm","sb","tmd"};
  9.         for (int i = 0; i < cyuyan.length; i++) {
  10.             said =said.replace(cyuyan[i],"***");
  11.         }
  12.         System.out.println(said);
  13.     }
  14. }
复制代码
注意:字符串是常量,他们的值在创建之后不能被改变的。
二、StringBuilder

1.StringBuilder概述

StringBuilder可以当作是一个容器,创建之后内里的内容是可变的


  • 作用:进步字符串的利用效率
2。StringBuilder构造方法

方法名阐明public StringBuilder ()创建一个空缺可变字符串对象,不含有任何内容public StringBuilder (String str )根据字符串的内容,来创建可变字符串对象 3.StringBuilder常用方法

方法名阐明public StringBuilder append (恣意范例)添加数据,并返回对象自己public StringBuilder reverse ()反转容器中的内容public int length()返回长度(字符出现的个数)public String toString通过toString()就可以实现把StringBuilder 转换成String
  1. public class builder {
  2.     public static void main(String[] args) {
  3.         //1.创建对象
  4.         StringBuilder sb = new StringBuilder("abc");
  5.         
  6.         //2.添加功能
  7.         sb.append("def");
  8.         sb.append("ghi");
  9.         sb.append("jkl");
  10.         sb.append("mno");
  11.         
  12.         //3.反转功能
  13.         sb.reverse();
  14.         
  15.         //4.获取长度
  16.         int length = sb.length();
  17.     }
  18. }
复制代码
  1. public class demoo {
  2.     public static void main(String[] args) {
  3.         //1.创建对象
  4.         StringBuilder sb = new StringBuilder("abc");
  5.         //2.添加功能
  6.         sb.append("def");
  7.         sb.append("ghi");
  8.         sb.append("jkl");
  9.         sb.append("mno");
  10.         System.out.println(sb);
  11.         //3.再把StringBuilder变回String
  12.         //为什么要把StringBuilder变回String呢?
  13.         //因为StringBuilder是一个可变的字符串,而String是一个不可变的字符串,所以我们需要把StringBuilder变回String,才能使用String的方法
  14.         String str = sb.toString();
  15.         System.out.println(str);
  16.     }
  17. }
复制代码
链式编程
当我们在调用一个方法的时候,不必要用变量担当他的效果,可以继续调用其他方法
  1. import java.util.Scanner;
  2. public class lianshi {
  3.     public static void main(String[] args) {
  4.         //链式编程:
  5.         //当我们在调用一个方法的时候,这个方法的返回值是一个对象,我们可以继续调用这个对象的方法。
  6.         //这种方式叫做链式编程。
  7.         int len = getString().substring(1).length();
  8.         System.out.println(len);
  9.     }
  10.     public static String getString() {
  11.         Scanner sc = new Scanner(System.in);
  12.         System.out.println("请输入一个字符串:");
  13.         String s = sc.next();
  14.         return s;
  15.     }
  16. }
复制代码
  1. //链式编程练习
  2. public class lioain {
  3.     public static void main(String[] args) {
  4.         //1.创建对象
  5.         StringBuilder sb = new StringBuilder("abc");
  6.         //2.添加功能
  7.         sb.append("def").append("ghi").append("jkl").append("mno");
  8.         System.out.println(sb);
  9.         String s = sb.toString();
  10.         System.out.println(s);
  11.     }
  12. }
复制代码
  1. //判断是不是回文串
  2. import java.util.Scanner;
  3. public class xio {
  4.     public static void main(String[] args) {
  5.         Scanner sc = new Scanner(System.in);
  6.         System.out.println("请输入一个字符串:");
  7.         //键盘录入一个字符串
  8.         String str = sc.next();
  9.         //将字符串反转
  10.         String sb = new StringBuilder().append(str).reverse().toString();
  11.         //判断是否是回文串
  12.         if (sb.equals(str)) {
  13.             System.out.println("是回文串");
  14.         }else {
  15.             System.out.println("不是回文串");
  16.         }
  17.     }
  18. }
复制代码
  1. //需求:定义方法,把int数组中的数据类型按照指定的格式拼接换成一个字符串返回,调用方法,并在控制台输出结果
  2. public class ding {
  3.     public static void main(String[] args) {
  4.         int[] arr = {1,2,3,4,5,6,7,8,9,10};
  5.         System.out.println(getArray(arr));
  6.     }
  7.     public static String getArray(int[] arr) {
  8.         StringBuilder sb = new StringBuilder();
  9.         sb.append("[");
  10.         for (int i = 0; i < arr.length; i++) {
  11.             if (i == arr.length - 1) {
  12.                 sb.append(arr[i]);
  13.             }else {
  14.                 sb.append(arr[i]).append(",");
  15.             }
  16.         }
  17.         sb.append("]");
  18.         return sb.toString();
  19.     }
  20. }
复制代码
三、StringJoiner

我们为什么要学StringJoiner?
我们原来在学习String时拼接元素太泯灭时间,于是有了StringBuilder
但是我们在上面训练中,在打印字符串格式时,要做诸多限制,不是很方便于是
就有了StringJoiner。

1.StringJoiner概述



  • StringJoiner跟StringBuilder一样,也可以当作是一个容器,创建之后内里的内容是可变的
  • 作用:进步字符串的利用效率,而且代码编写的特殊简洁,但是市场上很少有人看
  • JDK8出现的
2.StringJoiner的构造方法

没有空参构造
方法名阐明pubilc StringJoiner(隔断符号)创建一个StringJoiner对象,指定拼接时的隔断符号pubilc StringJoiner(隔断符号,开始符号,结束符号 )创建一个StringJoiner对象,指定拼接时的隔断符号、开始符号、结束符号
  1. StringJoiner sj = new StringJoiner("---");
  2. 1--2--3
复制代码
  1. StringJoiner sj = new StringJoiner(",","[","]");
  2. [1,2,3]
复制代码
3.StringJoiner的成员方法

方法名阐明public StringJoiner add (添加的内容)添加数据,并返回对象自己public int length()返回长度(字符出现的个数)public String toString()返回一个字符串(该字符串就是拼接之后的效果)
  1. import java.util.StringJoiner;
  2. public class joner {
  3.     public static void main(String[] args) {
  4.         //1.创建对象
  5.         StringJoiner sj = new StringJoiner("---");
  6.         //2.添加功能
  7.         sj.add("adc").add("def").add("ghi");
  8.         System.out.println(sj);
  9.         
  10.         
  11.         //3.创建对象2
  12.         //delimiter: 分隔符
  13.         //prefix: 前缀
  14.         //suffix: 后缀
  15.         StringJoiner sj2 = new StringJoiner(" ", "[", "]");
  16.         //4.添加功能
  17.         sj2.add("adc").add("def").add("ghi");
  18.         System.out.println(sj2);
  19.     }
  20. }
  21. //adc---def---ghi
  22. //[adc def ghi]
复制代码
  1. import java.util.StringJoiner;
  2. public class zifu {
  3.     public static void main(String[] args) {
  4.         StringJoiner sj = new StringJoiner(",","[","]");
  5.         int len = sj.add("aaa").add("bbb").add("ccc").length();
  6.         //len不仅是字符串的长度,还包括了[]和,的长度
  7.         System.out.println(len);
  8.     }
  9. }
  10. //13
复制代码
length不仅是字符串的长度,还包括符号的长度
总结:String与StringBuilder与StringJoiner

String:
表示字符串的类,定义了许多利用字符串的方法
StringBuilder:
一个可变的利用字符串的容器。
可以高效的拼接字符串,还可以将容器内里的内容反转
StringJoiner:
JDK8出现的一个可变的利用字符串的容器,可以高效,方便的拼接字符串。
在拼接的时候,可以指定隔断符号,开始符号,结束符号。
四、字符串原理

扩展底层原理1:字符串存储的内存原理



  • 直接赋值会复用字符串常量池中的
  • new出来不会复用,而是开辟一个新的空间
扩展底层原理2:==号比较的到底是什么?



  • 基本数据范例比较数据值
  • 引用数据范例比较地址值
扩展底层原理3:字符串拼接的底层原理

等号的右边没有变量

  1. public class Test {
  2.     public static void main (String [] args){
  3.         String s = "a"+ "b"+"c";
  4.         System.out.println(s);
  5.     }
  6. }
复制代码
拼接的时候没有变量,都是字符串。触发字符串的优化机制。在编译的时候就已经是最终的效果了。

等号的右边有变量

  1. public class Test {
  2.     public static void main (String [] args ){
  3.         String s1 = "a";
  4.         String s2 = s1 + "b";
  5.         String s3 = s2 + "c";
  6.         System.out.println (s3);
  7.         
  8.     }
  9. }
复制代码
在拼接的时候有变量,JDK8 以前底层会使用StringBuilder

内存分析:
1、进入 main 方法
在栈为 main 方法创建栈帧,用于存局部变量。
2、执行变量赋值
String s1 = “a”;:
栈中创建 s1,若字符串常量池无 "a" 则创建,将其引用赋给 s1。
String s2 = s1 + “b”;:
栈中创建 s2,堆中创建 StringBuilder 拼接 s1 和 "b"(若常量池无 "b" 则创建),生成新字符串 "ab" 存于堆,引用赋给 s2。
String s3 = s2 + “c”;:
栈中创建 s3,堆中新建 StringBuilder 拼接 s2 和 "c"(若常量池无 "c" 则创建),生成新字符串 "abc" 存于堆,引用赋给 s3。
3、输出效果
从栈取s3引用,找到堆中 "abc" 输出。
4、方法结束
main 栈帧烧毁,局部变量消失,堆对象等待垃圾回收,常量池字符串保留至程序结束。
**总结:**一个加号,堆内存中俩对象
  1. public class Test {
  2.     public static void main (String [] args ){
  3.         String s1 = "a";
  4.         String s2 = s1 + "b";
  5.         String s3 = s2 + "c";
  6.         System.out.println (s3);
  7.         
  8.     }
  9. }
复制代码
字符串拼接的时候有变量参与:
在内存中创建了许多对象,浪费空间,时间也非常的慢
结论:如果许多字符串变量拼接,不要直接+。在底层会创建多个对象,浪费时间,浪费性能
总结:



  • 如果没有变量参与,都是字符串直接相加,编译之后就是拼接之后的效果,会复用串池中的字符串
  • 如果没有变量参与,每一行拼接的代码,都会在内存中创建新的字符串,浪费内存
扩展底层原理4:StringBuilder进步效率原理图

  1. public class Test {
  2.     public static void main (String [] args){
  3.         StringBuilder sb = new StringBuilder();
  4.         sb.append("a");
  5.         sb.append("b");
  6.         sb.append("c");
  7.         System.out.println(sb);
  8.     }
  9. }
复制代码

StringBuilder 是一个可变的容器
内存分析
1、进入 main 方法
JVM 在栈为 main 方法创建栈帧,用于存储局部变量。
2、执行代码
StringBuilder sb = new StringBuilder();:
栈中创建局部变量 sb,堆中创建 StringBuilder 对象,sb 指向该对象。
sb.append(“a”);:
查抄字符串常量池,若没有 "a" 则创建,StringBuilder 对象将 "a" 内容添加到自身存储地区。
sb.append(“b”);:
同理,若常量池无 "b" 则创建,StringBuilder 追加 "b"。
sb.append(“c”);:
若常量池无 "c" 则创建,StringBuilder 追加 "c"。
System.out.println(sb);:
从栈中获取 sb 引用,找到堆中 StringBuilder 对象,输出其内容。
2、方法结束
main 方法栈帧烧毁,局部变量 sb 消失,堆中 StringBuilder 对象等待垃圾回收,字符串常量池中的 "a"、"b"、"c" 保留到程序结束。
  1. //面试水题:
  2. //问题:下列代码的运行结果是什么?
  3. public static void main (String [] args ){
  4.     String s1 = "abc";//记录串池中的地址值
  5.     String s2 = "ab";
  6.     String s3 = s2 + "c";//新new出来的对象,地址值不一样
  7.     System.out.println(s1==s3);
  8.     //==比较的是引用局部变量的地址值
  9. }
  10. //flase
复制代码
字符串拼接的时候,如果有变量:
JDK8:系统底层会自动创建一个StringBuilder对象,然后再调用其append方法完成拼接。拼接后,再调用其toString方法转换为String范例,而toString方法的底层是直接new了一个字符串对象。
JDK8版本:系统会预估要字符串拼接之后的总巨细,把要拼接的内容都放在数组中,此时也是产生一个新的字符串。
  1. public class Test{
  2.     public static void main (String [] args ){
  3.         String s1 = "abc";//记录串池中的地址值
  4.         String s2 = "a"+"b"+"c";
  5.         //没有变量,触发优化机制,编译时,就会将“a”+"b"+"c"拼接为"abc"
  6.         //复用串池中的字符串
  7.         System.out.println(s1==s2);
  8.     }
  9. }
  10. //ture
复制代码
总结:



  • 全部要拼接的内容都会往StringBuilder中放,不会创建许多无用的空间,节省内存
扩展底层原理5:StringBuilder的源码分析



  • 默认创建一个长度为16的字节数组
  • 添加的内容长度小于16,直接存
  • 添加的内容大于16会扩容 (原来的容量 *2 +2)
  • 如果扩容之后还不够,以实际长度为准
System.out.println(sb);:
从栈中获取 sb 引用,找到堆中 StringBuilder 对象,输出其内容。
2、方法结束
main 方法栈帧烧毁,局部变量 sb 消失,堆中 StringBuilder 对象等待垃圾回收,字符串常量池中的 "a"、"b"、"c" 保留到程序结束。
  1. //面试水题:
  2. //问题:下列代码的运行结果是什么?
  3. public static void main (String [] args ){
  4.     String s1 = "abc";//记录串池中的地址值
  5.     String s2 = "ab";
  6.     String s3 = s2 + "c";//新new出来的对象,地址值不一样
  7.     System.out.println(s1==s3);
  8.     //==比较的是引用局部变量的地址值
  9. }
  10. //flase
复制代码
字符串拼接的时候,如果有变量:
JDK8:系统底层会自动创建一个StringBuilder对象,然后再调用其append方法完成拼接。拼接后,再调用其toString方法转换为String范例,而toString方法的底层是直接new了一个字符串对象。
JDK8版本:系统会预估要字符串拼接之后的总巨细,把要拼接的内容都放在数组中,此时也是产生一个新的字符串。
  1. public class Test{
  2.     public static void main (String [] args ){
  3.         String s1 = "abc";//记录串池中的地址值
  4.         String s2 = "a"+"b"+"c";
  5.         //没有变量,触发优化机制,编译时,就会将“a”+"b"+"c"拼接为"abc"
  6.         //复用串池中的字符串
  7.         System.out.println(s1==s2);
  8.     }
  9. }
  10. //ture
复制代码
总结:



  • 全部要拼接的内容都会往StringBuilder中放,不会创建许多无用的空间,节省内存
扩展底层原理5:StringBuilder的源码分析



  • 默认创建一个长度为16的字节数组
  • 添加的内容长度小于16,直接存
  • 添加的内容大于16会扩容 (原来的容量 *2 +2)
  • 如果扩容之后还不够,以实际长度为准

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

魏晓东

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表