StringTable

news2024/9/28 17:30:06

文章目录

      • 1. String的基本特性
      • 2. String的内存分配
      • 3. String的基本操作
      • 4.字符串的拼接操作
      • 5. intern()的使用
      • 6. G1中的String去重操作

1. String的基本特性

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

2. String的内存分配

在这里插入图片描述在这里插入图片描述
使用String的intern方法可以把字符串加入到字符串常量池。同时可以使用该方法来证明JDK8中字符串常量池存储在堆里面。

/**
 * jdk6中:
 * -XX:PermSize=6m -XX:MaxPermSize=6m -Xms6m -Xmx6m
 *
 * jdk8中:
 * -XX:MetaspaceSize=6m -XX:MaxMetaspaceSize=6m -Xms6m -Xmx6m
 * @author shkstart  shkstart@126.com
 * @create 2020  0:36
 */
public class StringTest3 {
    public static void main(String[] args) {
        //使用Set保持着常量池引用,避免full gc回收常量池行为
        Set<String> set = new HashSet<String>();
        //在short可以取值的范围内足以让6MB的PermSize或heap产生OOM了。
        short i = 0;
        while(true){
            set.add(String.valueOf(i++).intern());
        }
    }
}

在这里插入图片描述

3. String的基本操作

在这里插入图片描述在这里插入图片描述在这里插入图片描述

4.字符串的拼接操作

在这里插入图片描述如下的s1 + s2 的执行细节:(变量s是我临时定义的)
① StringBuilder s = new StringBuilder();
② s.append(“a”)
③ s.append(“b”)
④ s.toString() --> 约等于 new String(“ab”)

    补充:在jdk5.0之后使用的是StringBuilder,在jdk5.0之前使用的是StringBuffer
1) 字符串拼接操作不一定使用的是StringBuilder!
   如果拼接符号左右两边都是字符串常量或常量引用,则仍然使用编译期优化,即非StringBuilder的方式。
2) 针对于final修饰类、方法、基本数据类型、引用数据类型的量的结构时,能使用上final的时候建议使用上。
package com.atguigu.java1;

import org.junit.Test;

/**
 * 字符串拼接操作
 * @author shkstart  shkstart@126.com
 * @create 2020  0:59
 */
public class StringTest5 {
    @Test
    public void test1(){
        String s1 = "a" + "b" + "c";//编译期优化:等同于"abc"
        String s2 = "abc"; //"abc"一定是放在字符串常量池中,将此地址赋给s2
        /*
         * 最终.java编译成.class,再执行.class
         * String s1 = "abc";
         * String s2 = "abc"
         */
        System.out.println(s1 == s2); //true
        System.out.println(s1.equals(s2)); //true
    }

    @Test
    public void test2(){
        String s1 = "javaEE";
        String s2 = "hadoop";

        String s3 = "javaEEhadoop";
        String s4 = "javaEE" + "hadoop";//编译期优化
        //如果拼接符号的前后出现了变量,则相当于在堆空间中new String(),具体的内容为拼接的结果:javaEEhadoop
        String s5 = s1 + "hadoop";
        String s6 = "javaEE" + s2;
        String s7 = s1 + s2;

        System.out.println(s3 == s4);//true
        System.out.println(s3 == s5);//false
        System.out.println(s3 == s6);//false
        System.out.println(s3 == s7);//false
        System.out.println(s5 == s6);//false
        System.out.println(s5 == s7);//false
        System.out.println(s6 == s7);//false
        //intern():判断字符串常量池中是否存在javaEEhadoop值,如果存在,则返回常量池中javaEEhadoop的地址;
        //如果字符串常量池中不存在javaEEhadoop,则在常量池中加载一份javaEEhadoop,并返回次对象的地址。
        String s8 = s6.intern();
        System.out.println(s3 == s8);//true
    }

    @Test
    public void test3(){
        String s1 = "a";
        String s2 = "b";
        String s3 = "ab";
        /*
        如下的s1 + s2 的执行细节:(变量s是我临时定义的)
        ① StringBuilder s = new StringBuilder();
        ② s.append("a")
        ③ s.append("b")
        ④ s.toString()  --> 约等于 new String("ab")

        补充:在jdk5.0之后使用的是StringBuilder,在jdk5.0之前使用的是StringBuffer
         */
        String s4 = s1 + s2;//
        System.out.println(s3 == s4);//false
    }
    /*
    1. 字符串拼接操作不一定使用的是StringBuilder!
       如果拼接符号左右两边都是字符串常量或常量引用,则仍然使用编译期优化,即非StringBuilder的方式。
    2. 针对于final修饰类、方法、基本数据类型、引用数据类型的量的结构时,能使用上final的时候建议使用上。
     */
    @Test
    public void test4(){
        final String s1 = "a";
        final String s2 = "b";
        String s3 = "ab";
        String s4 = s1 + s2;
        System.out.println(s3 == s4);//true
    }
    //练习:
    @Test
    public void test5(){
        String s1 = "javaEEhadoop";
        String s2 = "javaEE";
        String s3 = s2 + "hadoop";
        System.out.println(s1 == s3);//false

        final String s4 = "javaEE";//s4:常量
        String s5 = s4 + "hadoop";
        System.out.println(s1 == s5);//true

    }

    /*
    体会执行效率:通过StringBuilder的append()的方式添加字符串的效率要远高于使用String的字符串拼接方式!
    详情:① StringBuilder的append()的方式:自始至终中只创建过一个StringBuilder的对象
          使用String的字符串拼接方式:创建过多个StringBuilder和String的对象
         ② 使用String的字符串拼接方式:内存中由于创建了较多的StringBuilder和String的对象,内存占用更大;如果进行GC,需要花费额外的时间。

     改进的空间:在实际开发中,如果基本确定要前前后后添加的字符串长度不高于某个限定值highLevel的情况下,建议使用构造器实例化:
               StringBuilder s = new StringBuilder(highLevel);//new char[highLevel]
     */
    @Test
    public void test6(){

        long start = System.currentTimeMillis();

//        method1(100000);//4014
        method2(100000);//7

        long end = System.currentTimeMillis();

        System.out.println("花费的时间为:" + (end - start));
    }

    public void method1(int highLevel){
        String src = "";
        for(int i = 0;i < highLevel;i++){
            src = src + "a";//每次循环都会创建一个StringBuilder、String
        }
//        System.out.println(src);

    }

    public void method2(int highLevel){
        //只需要创建一个StringBuilder
        StringBuilder src = new StringBuilder();
        for (int i = 0; i < highLevel; i++) {
            src.append("a");
        }
//        System.out.println(src);
    }
}

5. intern()的使用

在这里插入图片描述
在这里插入图片描述

/**
 * 题目:
 * new String("ab")会创建几个对象?看字节码,就知道是两个。
 *     一个对象是:new关键字在堆空间创建的
 *     另一个对象是:字符串常量池中的对象"ab"。 字节码指令:ldc
 *
 * 思考:
 * new String("a") + new String("b")呢?
 *  对象1:new StringBuilder()
 *  对象2: new String("a")
 *  对象3: 常量池中的"a"
 *  对象4: new String("b")
 *  对象5: 常量池中的"b"
 *
 *  深入剖析: StringBuilder的toString():
 *      对象6 :new String("ab")
 *       强调一下,toString()的调用,在字符串常量池中,没有生成"ab"
 *
 * @author shkstart  shkstart@126.com
 * @create 2020  20:38
 */
public class StringNewTest {
    public static void main(String[] args) {
//        String str = new String("ab");

        String str = new String("a") + new String("b");
    }
}

/**
 * 如何保证变量s指向的是字符串常量池中的数据呢?
 * 有两种方式:
 * 方式一: String s = "shkstart";//字面量定义的方式
 * 方式二: 调用intern()
 *         String s = new String("shkstart").intern();
 *         String s = new StringBuilder("shkstart").toString().intern();
 *
 * @author shkstart  shkstart@126.com
 * @create 2020  18:49
 */
public class StringIntern {
    public static void main(String[] args) {

        String s = new String("1");
        s.intern();//调用此方法之前,字符串常量池中已经存在了"1"
        String s2 = "1";
        System.out.println(s == s2);//jdk6:false   jdk7/8:false


        String s3 = new String("1") + new String("1");//s3变量记录的地址为:new String("11")
        //执行完上一行代码以后,字符串常量池中,是否存在"11"呢?答案:不存在!!
        s3.intern();//在字符串常量池中生成"11"。如何理解:jdk6:创建了一个新的对象"11",也就有新的地址。
                                            //         jdk7:此时常量中并没有创建"11",而是创建一个指向堆空间中new String("11")的地址
        String s4 = "11";//s4变量记录的地址:使用的是上一行代码代码执行时,在常量池中生成的"11"的地址
        System.out.println(s3 == s4);//jdk6:false  jdk7/8:true
    }
}

在这里插入图片描述在这里插入图片描述

public class StringIntern1 {
    public static void main(String[] args) {
        //StringIntern.java中练习的拓展:
        String s3 = new String("1") + new String("1");//new String("11")
        //执行完上一行代码以后,字符串常量池中,是否存在"11"呢?答案:不存在!!
        String s4 = "11";//在字符串常量池中生成对象"11"
        String s5 = s3.intern();
        System.out.println(s3 == s4);//false
        System.out.println(s5 == s4);//true
    }
}

在这里插入图片描述

/**
 * @author shkstart  shkstart@126.com
 * @create 2020  20:17
 */
public class StringExer1 {
    public static void main(String[] args) {
        String s = new String("a") + new String("b");//new String("ab")
        //在上一行代码执行完以后,字符串常量池中并没有"ab"

        String s2 = s.intern();//jdk6中:在串池中创建一个字符串"ab"
                               //jdk8中:串池中没有创建字符串"ab",而是创建一个引用,指向new String("ab"),将此引用返回

        System.out.println(s2 == "ab");//jdk6:true  jdk8:true
        System.out.println(s == "ab");//jdk6:false  jdk8:true
    }
}
/**
 *
 * @author shkstart  shkstart@126.com
 * @create 2020  20:26
 */
public class StringExer2 {
    public static void main(String[] args) {
        String s1 = new String("ab");//执行完以后,会在字符串常量池中会生成"ab"                         // false
//        String s1 = new String("a") + new String("b");执行完以后,不会在字符串常量池中会生成"ab"  // true
        s1.intern();
        String s2 = "ab";
        System.out.println(s1 == s2);
    }
}

intern的效率测试
结论:对于程序中大量存在存在的字符串,尤其其中存在很多重复字符串时,使用intern()可以节省内存空间。

/**
 * 使用intern()测试执行效率:空间使用上
 *
 * 结论:对于程序中大量存在存在的字符串,尤其其中存在很多重复字符串时,使用intern()可以节省内存空间。
 *
 *
 * @author shkstart  shkstart@126.com
 * @create 2020  21:17
 */
public class StringIntern2 {
    static final int MAX_COUNT = 1000 * 10000;
    static final String[] arr = new String[MAX_COUNT];

    public static void main(String[] args) {
        Integer[] data = new Integer[]{1,2,3,4,5,6,7,8,9,10};

        long start = System.currentTimeMillis();
        for (int i = 0; i < MAX_COUNT; i++) {
//            arr[i] = new String(String.valueOf(data[i % data.length]));
            arr[i] = new String(String.valueOf(data[i % data.length])).intern();

        }
        long end = System.currentTimeMillis();
        System.out.println("花费的时间为:" + (end - start));

        try {
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.gc();
    }
}

在这里插入图片描述

6. G1中的String去重操作

在这里插入图片描述在这里插入图片描述在这里插入图片描述
注:本文是学习 尚硅谷宋红康JVM全套教程(详解java虚拟机)所做笔记。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/55756.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PL7022/PL7022B原厂双节/两节锂电池串联充电IC和保护IC

双节锂电池串联管理系列选型表&#xff1a; 型号 封装 功能 PL7022B SOT23-6 双节4.2V锂电池串联保护电路 PL7022 SOT23-6 双节4.35V锂电池串联保护电路 PL7501C ESOP8 升压型双节锂电池串联充电电路&#xff08;VIN:5V&#xff09; PL7222 ESOP8 降压型双节锂电…

ABC 分析法(帕累托分析法、2/8分析法)

在任何特定群体中&#xff0c;重要的因子通常只占少数&#xff0c;而不重要的因子则占多数&#xff0c;因此只要能控制具有重要性的少数因子即能控制全局。例如&#xff0c;在企业中&#xff0c;通常认为它80%的利润来自于20%的项目或重要客户&#xff1b;全球最富有的 20% 人口…

帮公司面试了一个33岁的程序员,只因这一个细节,被我一眼看穿是培训班出来的,没啥工作经验...

首先&#xff0c;我说一句&#xff1a;培训出来的&#xff0c;优秀学员大有人在&#xff0c;我不希望因为带着培训的标签而无法达到用人单位和候选人的双向匹配&#xff0c;是非常遗憾的事情。 最近&#xff0c;在网上看到这样一个留言&#xff0c;引发了程序员这个圈子不少的…

基于功能安全的车载计算平台开发:硬件层面

作为车载智能计算平台功能软件与系统软件的载体&#xff0c;硬件的失效可能直接导致功能软件输出不可信任的结果&#xff0c;从而违背安全目标。由于硬件故障在硬件生命周期中发生时间的随机性&#xff0c;在通过改善流程降低系统性失效的同时&#xff0c;ISO 26262功能安全标准…

Mysql的时间类型选定:Datetime,Timestamp,Bigint

1. 基本区别: 2. 其他特性: 1. TIMESTAMP是以utc格式存储,会自动检索当前时区对时间进行转换,而DATETIME不会。 2. 存入null时,TIMESTAMP会自动存储当前时间,而DATETIME存储null值。 3. 时间计算: DATETIME翻译为汉语即"时间戳",它是当前时间到 Unix元年(1…

RabbitMQ_消息的TTL与死信队列

什么是消息的TTL? TTL time to live&#xff0c;消息的TTL 消息的存活时间或过期时间 什么是死信队列&#xff1f; 当队列中的消息到达存活时间或过期时间后&#xff0c;若未设置死信队列&#xff0c;则该消息将被抛弃&#xff0c;反之则转入死信队列 死信队列 配置类 死…

Polygon zkEVM R1CS与Plonk电路转换

1. 引言 前序博客有&#xff1a; Polygon zkEVM的pil-stark Fibonacci状态机初体验Polygon zkEVM的pil-stark Fibonacci状态机代码解析rank-1 constraint system R1CS 由上图可知&#xff0c;zkEVM会借助SNARK来“验证&#xff08;&#xff08;验证STARK证明&#xff09;的SN…

博安生物再次冲刺港交所上市:负债规模高企,持续出现亏损

11月30日&#xff0c;山东博安生物技术股份有限公司&#xff08;下称“博安生物”&#xff09;再次向港交所递交招股书&#xff0c;准备在港交所主板上市。据贝多财经了解&#xff0c;博安生物曾于2022年5月13日递表&#xff0c;现已“失效”。 相较于此前招股书&#xff0c;博…

【图像分割】基于神经气体网络的图像分割与量化(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

了解抖音小程序的评级。为什么我的抖音小程序申请不了某个功能?

目录前言评级评级运营规范评级周期查看评级评级对应的权益小程序评级审核驳回场景信用分常见问题为什么我的小程序不能挂载短视频&#xff1f;前言 小程序评级体系是衡量小程序整体质量的参照&#xff0c;也是小程序获取对应权益的指南&#xff0c;旨在推动、鼓励开发者提升小…

matlab如何从信号中去除60 Hz Hum电源线噪声

美国和其他几个国家的交流电流以60赫兹的频率振荡。这些振荡经常会破坏测量值并且必须减去。 最近我们被客户要求撰写关于信号去噪数据的研究报告&#xff0c;包括一些图形和统计输出。 在存在60 Hz电源线噪声的情况下研究模拟仪器输入端的开环电压。电压以1 kHz采样。 lo…

C/C++内存管理(malloc/calloc/realloc/free/new/delete/operator new/operator delete)

目录 C语言中动态内存管理方式&#xff1a;malloc/calloc/realloc/free C内存管理方式:new/delete operator new与operator delete函数 new和delete的实现原理 malloc/free和new/delete的区别 (用法上和底层) 内存泄漏 C/C中程序内存区域划分&#xff1a; 1. 栈又叫堆栈…

Linux C简单服务器模型解析及完整代码

Linux C简单服务器模型解析及完整代码1.服务器端流程及解析2.服务器端代码3.客户端流程及解析4.客户端代码5.不足之处&#xff08;注&#xff1a;流程解析可结合相应代码处一起理解&#xff09;1.服务器端流程及解析 服务器端做的事情&#xff1a; 1.创建监听的套接字。 int s…

JAVA培训之数据库表关联关系

数据库表的关联关系有如下三种&#xff1a; 一对多 一对一 多对多 一对多的关系比较常见&#xff0c;我们在之前练习的都是一对多的关系操作&#xff0c;因此这里就不再重复介绍了。 1.一对一关系 在现实生活中&#xff0c;丈夫与妻子之间的关系就是一对一的关系&…

参数估计(1)-参数的点估计

为了考察总体X 的分布&#xff0c;我们将在2.4 节给出经验分布函数&#xff0c;并在总体X为连续型情形下绘制了频率直方图从中可大致看出总体的分布情况或分布形式&#xff0c;但总体分布中包含的参数往往不知&#xff0e;如何根据抽样对未知参数进行估计&#xff0c;就是本章讨…

pandas分组与聚合groupby()函数详解

一、groupby分组与聚合 分组与聚合通常是分析数据的一种方式&#xff0c;通常与一些统计函数一起使用&#xff0c;查看数据的分组情况 DataFrame.groupby(byNone, axis0, levelNone, as_indexTrue, sortTrue, group_keys_NoDefault.no_default, squeeze_NoDefault.no_default…

基于docker部署实现接口自动化持续集成

01 jenkins介绍及docker部署 Jenkins是一个开源软件项目&#xff0c;是基于Java开发的一种持续集成工具&#xff0c;用于监控持续重复的工作&#xff0c;旨在提供一个开放易用的软件平台&#xff0c;使软件项目可以进行持续集成 1、创建网络 2、下载并运行 docker:dind镜像…

思科路由器地址转换配置

思科路由器地址转换1.端口复用(PAT)2.配置PAT1.端口复用(PAT) 复用地址转换也称为端口地址转换&#xff08;Port Address Translation&#xff0c;PAT&#xff09;&#xff0c;首先是一种动态地址转换。路由器将通过记录地址、应用程序端口等唯一标识一个转换。通过这种转换&am…

Linux 负载均衡介绍

Linux 负载均衡介绍 LB LB&#xff1a;Load Balancing&#xff0c;负载均衡&#xff08;增加处理能力&#xff09;,有高可用能力&#xff0c;但不是高可用集群负载均衡集群&#xff0c;是以提高服务的并发处理能力为根本着眼点 负载均衡设备分类 1.软件负载均衡设备 (1)LVS&…

肝病患者关爱与病例管理

国内的肝病患者人数多达3亿人&#xff0c;并且还在逐年增多。 为慢性肝炎患者提供患者教育、病情自我管理、病友交流、医患交流等一系列的关怀行动&#xff0c;为医生提供病例数据管理系统平台推出了“肝病患者关爱与病例管理系统" 用户需求 平台覆盖用户群 中国肝病患者…