• String类 - 下篇


     
    String 类下篇
     

    String 类 - 上篇 链接

    前言: 上篇我们学习了 Stirng类的一些常用方法, 外加初步了解了一下我们的字符串常量池, 本文 继上文,完成String类的剩下知识点 。
     

    1.字符串的不可变性

     
    相比大家都 听过, 字符串 是 不可变 的 , 那么String类 是为什么是不可变的呢?

     

    在这里插入图片描述

    在我们现在的 知识储备上我们可以 认为 String 是不可改变的,但实际上我们 可以通过反射 进行 改变,反射将在后面学到,所以我们现在就认为 String类是不可改变的。

     
    既然我们知道了 字符串是不可改变的,那么我们要如何 去完成字符串的修改呢?
     

    字符串的修改

     

    这里先来看一段代码

    在这里插入图片描述

     
    这里我们就会产生 3 个对象 (注意: 这里没有算 String 类 中的 value 数组)

    在这里插入图片描述

     
    刚刚我们说过 我们的字符串是 不可 变的 ,我们并不能在原来的字符串上 进行修改, 只能重新生成 对象, 所以我们 要 尽量避免直接对String类型对象进行修改,因为String类是不能修改的,所有的修改都会创建新对象,效率非常低下。

     
    针对 说 : String类是不能修改的,所有的修改都会创建新对象,效率非常低下

     
    我们可 通过 代码来验证,这里 会涉及到 StringBuilder, StringBufferu , 正好将我们 接下要介绍的 这个两个 给 引出来

    public static void main(String[] args) {
        // 通过 System 底下的方法计算 时间戳
            long start = System.currentTimeMillis();
            String s = "";
            for (int i = 0; i < 10000; ++i) {
                s += i;
            }
            long end = System.currentTimeMillis();
            System.out.println(end - start);
    
            start = System.currentTimeMillis();
            StringBuffer sbf = new StringBuffer("");
            for (int i = 0; i < 10000; ++i) {
                sbf.append(i);
            }
            end = System.currentTimeMillis();
            System.out.println(end - start);
    
            start = System.currentTimeMillis();
            StringBuilder sbd = new StringBuilder();
            for (int i = 0; i < 10000; ++i) {
                sbd.append(i);
            }
            end = System.currentTimeMillis();
            System.out.println(end - start);
        }
    
    • 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

     
    补充: StringBuilder, StringBufferu 通过 append 进行拼接 不会产生 额外 的对象, 是在原来的字符串上完成拼接。

    所以 String 与 StringBuilder, StringBufferu 的 区别,就是 Stirng 每次 通过 + 拼接, 会产生新的对象 , 这里我们上面 三个 拼接 1w次, 就会有明显 的 区别 。

    在这里插入图片描述

     

    运行 程序会明显的发现我们的 String 类 拼接的 时间 是 比 StringBuilder, StringBufferu 要慢的多 。

     
    这里我们 就需要注意: 如果在循环 中拼接 字符串,我们 要尽量 不用使用 String , 尽量使用 StringBuilder, StringBufferu

     
    下面我们就来 学习 一下 StringBuilder 和 StringBufferu

     

    StringBuilder和StringBuffer

     
    前引 :

    在这里插入图片描述

     
    刚刚说过, 通过String 拼接是非常慢的 为什么 慢 , 慢到哪里 呢 ?
     
    这里我们就需要 观察一下 他的 汇编 ,

    在这里插入图片描述

     
    这里 我们 可以 通过 StringBuilder 还原 成 上面 String 拼接的 效果

    在这里插入图片描述

     
    这个代码 就与 String 拼接的 代码 是 等价的。

     
    下面就来 改进 用一个 StringBuilder 来完成我们的任务 ,这样完成了我们的简化,少了频繁 new 对象的 过程。

    在这里插入图片描述

    下面就来对 讲一讲 StringBuilder 和 StringBuffer 的 区别

     

    StringBuilder 和 StringBuffer的区别

    区别StringBuilderStringBuffer
    相同点是 一个 类 能表达字符串是一个类 能表达字符串
    相同点不能直接 赋值不能直接赋值
    不同点线程不安全线程安全的

     
    图示: StringBuilder 和 StringBuffer 不能直接 赋值

    在这里插入图片描述

     
    这里我们就必须 new ,通过 构造方法,完成我们 的 赋值。

    在这里插入图片描述
     
    如果我们 通过 sout 直接打印 这两个对象是 能 成功的打印出 字符串的,这 是 为什么呢?

    在这里插入图片描述

     
    这里就与我们的线程安全 有关 , 这里我们 我们的 StringBuffer 是 线程安全的, 而 StringBuilder 是 线程不安全的, 啥是线程安全呢?
     
    这里 暂且 提一嘴 , 后面学到线程的时候 详细讲解 , 这里 只要知道 这两个类那个是线程安全的 那个是线程 不安全的 就好。

    这里就来简单举个例子 :

    在这里插入图片描述

    在这里插入图片描述

     
    通过上面 队 StringBuilder 和 StringBuffer 的讲解, 下面就来看 个面试 题
     

    String、StringBuffer、StringBuilder的区别

    答案 :

    1.String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.

     

    2.StringBuffer与StringBuilder大部分功能是相似的
     

    3.StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作

     
    最后 我们在来 完成几道 力扣 的 编程题 结束我们的 String类学习

    String类 oj题

     
    1.字符串中的第一个唯一字符 - 力扣(LeetCode)
    在这里插入图片描述

     
    2.字符串最后一个单词的长度_
    在这里插入图片描述

     
    3.验证回文串 - 力扣(LeetCode)

    在这里插入图片描述

     
    本题就一个难点, 如何 将 不是 字母 字符和 数组字符的排序,这里我们就可以单独写一个方法来判断, 如果 是 在 a 和 z 之间,或 0 到 9 之间就满足我们的条件,返回 true , 不是 返回 false 让 此时的 left 或 right 改变即可, 最后比较。 如果相等left ++ 和 right–,如果 不相等返回 false 就不是 回文串。 这我们同样可以使用 String类自带的方法。 这里就不使用了, 思路是一样 的,可以 自行了解

    class Solution {
    
        public static boolean isValidChar(char ch){
            if((ch >= 'a' && ch <= 'z')|| (ch >= '0' && ch <= '9')) {
                return true;
            }
            return false;
        }
        public boolean isPalindrome(String s) {
            s = s.toLowerCase();
            int left = 0;
            int right = s.length()-1;
            while(left < right){
                while(left < right && !isValidChar(s.charAt(left))){
                    //此时说明不是 字母
                    left++;
                }
                while(left < right && !isValidChar(s.charAt(right))){
                    right--;
                }
                // 走到这里说明left 和 right 处 都是字母
                if(s.charAt(left) != s.charAt(right)){
                    return false;
                }else {
                    left++;
                    right--;
                }
            }
            return 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
    • 30
    • 31

    在这里插入图片描述

     
    使用 String类 自带的方法

    class Solution {
        public boolean isPalindrome(String s) {
            int n = s.length();
            int left = 0;
            int right = n-1;
            while(left <= right) {
              while(left < right &&!Character.isLetterOrDigit(s.charAt(left))){
                  left++;
              }
              while(left< right &&!Character.isLetterOrDigit(s.charAt(right))) {
                  right--;
              }
              if(Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right))){
                  return false;
              }
              left++;
              right--;
            }
            return true;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

     
    本文结束 , 下文 预告: 异常。

  • 相关阅读:
    反射和序列化操作会破坏单例模式
    嵌入式FreeRTOS学习九,任务链表的构成,TICK时间中断和任务状态切换调度
    最接近的三数之和
    Java操作Elasticsearch(新增数据)
    CesiumJS 下载太慢了
    GD32F303固件库开发(14)----IIC之配置OLED
    大数据可视化优势在哪
    提高企业研发效率核心关键在打造组合应用建设
    UVA 10271 佳佳的筷子 Chopsticks [DP的基本运用]
    【Android笔记53】Android之实现应用程序中的画中画效果
  • 原文地址:https://blog.csdn.net/mu_tong_/article/details/126393560