• JavaSE之深度剖析String类



    提示:以下是本篇文章正文内容,Java系列学习将会持续更新

    一、初步认识

    1. String不是基本数据类型;而是Java中的一种包装类,重写了equals()方法。
    2. String类不可被继承,String对象是可不变的,因为被 final 修饰。
    3. String实例的字符串都是同过 char[] 储存的。
      在这里插入图片描述
    4. String 类中每一个看起来会修改 String 值的方法,实际上都是创建了一个全新的 String对象,以包含修改后的字符串内容。而最初的 String 对象则丝毫未动 。
      在这里插入图片描述
      回到目录…

    二、创建字符串的三种方式

    1. 直接赋值:只会开辟一块堆内存空间,并且该字符串对象可以自动保存在对象池中以供下次使用。
    String str = "Welcome to java";
    //推荐这种方式,只产生一个对象,节省空间
    
    • 1
    • 2
    1. 构造方法:会开辟两块堆内存空间,不会自动保存在对象池中。
    String str = new String("Welcome to java");
    //会产生两个对象,产生垃圾空间
    
    • 1
    • 2

    在这里插入图片描述
    这种方式的缺点:
     a. 如果使用String构造方法就会开辟两块堆内存空间,并且其中一块堆内存将成为垃圾空间(字符串常量 “hello” 也是一个匿名对象, 用了一次之后就不再使用了, 就成为垃圾空间, 会被 JVM 自动回收掉).
     b. 字符串共享问题. 同一个字符串可能会被存储多次, 比较浪费空间.

    // 可以手工入池,intern();不会创建垃圾空间
    String str1 = new String("hello").intern();
    String str2 = "hello";
    System.out.println(str1 == str2);  //输出:true
    
    • 1
    • 2
    • 3
    • 4
    1. 通过char[]数组创建字符串
    char[] data = {'h','e','l','l','o'};
    String str = new String(data);
    
    • 1
    • 2

    回到目录…

    三、字符串常量池

    String类的设计使用了共享设计模式

    在JVM底层实际上会自动维护一个字符串常量池:

    • 如果现在采用了直接赋值的模式进行String类的对象实例化操作,那么该实例化对象(字符串内容)将自动保存到这个对象池之中。
    • 如果下次继续使用直接赋值的模式声明String类对象,此时对象池之中如若有指定内容,将直接进行引用。如若没有,则开辟新的字符串对象而后将其保存在对象池之中以供下次使用。

    回到目录…

    四、理解字符串的不可变性

    String str = "hello";
    str = "world";
    System.out.println(str);  //输出:world
    
    • 1
    • 2
    • 3

    在这里插入图片描述
    回到目录…

    五、通过反射破坏String类

    通过反射强行破坏String类的封装,获取value数组进行改变。
    听听就行了:

    import java.lang.reflect.Field;
    public class Test {
        public static void main(String[] args) throws Exception{
    
            String str = "hello";
            //通过反射获取String类中的value数组
            Field field = String.class.getDeclaredField("value");
            //value的private定义取消掉
            field.setAccessible(true);
            //获取到str对象内部的value数组
            char[] value = (char[]) field.get(str);
            value[0] = 'H';
            System.out.println(str);   //输出:Hello
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    回到目录…

    六、与StringBuilder的关系

    为了方便字符串的修改,引入这两个类,它俩大部分功能是相同的。
     StringBuffer : 线程安全
     StringBuilder : 线程不安全,但是更快
    实际上它们与String类没有一点关系,没有血缘关系。

    出现字符串拼接 “+” 时,JVM会自动把字符串转换成StringBuilder类型的,调用其中的append()方法扩展字符串,避免产生过多的垃圾空间。

    回到目录…

    七、equals 和 == 的判断

    equals()方法是判断两个对象的内容是否相同,而 == 是判断是否为同一个对象。

    String str1 = new String("hello");
    String str2 = new String("hello");
    System.out.println(str1.equals(str2)); // true
    System.out.println(str1 == str2); // false
    
    • 1
    • 2
    • 3
    • 4
    String str3 = "world";
    String str4 = new String("world");
    System.out.println(str3.equals(str4)); // true
    System.out.println(str3 == str4); // false
    
    • 1
    • 2
    • 3
    • 4
    String str5 = "张三";
    String str6 = "张三";
    System.out.println(str5.equals(str6)); // true
    System.out.println(str5 == str6); // true
    
    • 1
    • 2
    • 3
    • 4

    回到目录…


    总结:
    提示:这里对文章进行总结:
    以上就是今天的学习内容,本文是JavaSE的学习,深度剖析String类,学习字符串创建的方式,字符串的不可变性,以及字符串常量池。之后的学习内容将持续更新!!!

  • 相关阅读:
    leetcode112.路径总和
    Ubuntu20.0下安装MySQL8.0
    C++之继承详解(万字讲解)
    一个月备考通过PMP
    netty - TimerWheel
    Idea设置
    用户自定义消息及层次划分
    【FAQ】【Push Kit】 华为怎么设置角标
    LLM之RAG理论(十)| RAT:一种协同CoT和RAG的 AI 提示策略,助力解决长任务推理和生成
    TDesign的input标签
  • 原文地址:https://blog.csdn.net/qq15035899256/article/details/126239264