栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JVM-String

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JVM-String

一、基本特性

1. 不可变性
String 类: 
   - 类被final修饰,不能被继承
   - 类中所有的属性被final修饰,不能去修改

1. 当对字符串重新赋值时,需要重写制定内存区域赋值,不能使用原有的value进行赋值
2. 当对现有的字符串进行连接操作时,需要重新制定内存区域赋值,不能使用原有的value进行赋值
3. 当调用String 的replace方法修改制定字符或字符串时,需要重新制定内存区域赋值,不能使用原有的value进行赋值

- 通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中
- 字符串常量池中,不会存放两个相同的元素
package com.erick.string.d01;

import org.junit.Test;

public class Demo01 {

    @Test
    public void method01() {
        String first = "erick";
        String second = "erick";

        
        System.out.println(first == second); // 指向同一个引用地址

        second = "hehe";
        System.out.println(first == second); // 引用地址已经变化
    }

    @Test
    public void method02() {
        String first = "Erick";
        String second = "Erick";
        second += "nihao";
        System.out.println(first==second);// 已经重新分配了一个新的数组
    }

    @Test
    public void method03(){
        String first = "Erick";
        String second = first.replace("E", "a");

        // 上面其实是生成了一个新的byte[]来存储字符串
        System.out.println(first==second);

    }
}
2. String底层HashTable
  • 字符串常量池中是不会存储相同内容的字符串的
String 的 String Pool 是一个固定大小的HashTable, 默认值大小长度是1009

- HashTable底层: 数组加链表的结构
- 这里说的大小长度指的是 数组长度,而不是总node的数量, 总node的数量可以无限存储
- 不过数组每个索引位置都存储元素的时候,查询起来就会慢 , 因为需要链表的遍历

- 如果放进去的String很多,就会造成Hash冲突严重,从而导致链表很长
  链表如果很长,查询时候比较慢

-XX:StringTableSize=20000    可以设置StringTable的长度

- jdk6中StringTable是固定的,如果常量池中的字符串过多就会导致效率下降很快,最小值随便设置

- jdk7中,StringTable的长度默认是60013, 
- jdk8时,1009是可以设置的最小值
- jdk11 : 默认长度为 65536
3. String 的内存分配
- Java包含八种基本数据类型和一种比较特殊的类型String
- 为了使得这些数据类型在运行过程中速度更快,更节省内存,都提供了一种常量池的概念
- 常量池就类似一个Java系统级别提供的缓存,八种基本数据类型的常量都是系统协调的
- String类型的常量池比较特殊,它的主要使用方法有两种

1.  直接使用“”声明的String对象会直接存储在常量池中
2.  不是“”声明的String对象,可以使用String提供的 intern()方法
  • JDK8中,常量池 存放在堆里面
4. String操作 4.1 字符串唯一性
  • 一个字符串已经出现了,则后续如果字符串的字面量和上面相同,则直接去常量池中取
  • 常量池中,不会保存两个完全相同的两个字符串
4.2 toString()
  • 任何类的toString()也会保存在常量池中
二、字符串拼接 1. 前端编译期间优化
    
    @Test
    public void test01() {
        String first = "a" + "b" + "c";
        String second = "abc";
        System.out.println(first == second); // true
        System.out.println(first.equals(second)); // true
    }
  • 对应字节码的反编译文件来查看
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.erick.string.d01;

import org.junit.Test;

public class Demo02 {
    public Demo02() {
    }

    @Test
    public void test01() {
        String first = "abc";
        String second = "abc";
        System.out.println(first == second);
        System.out.println(first.equals(second));
    }
}
  • 从字节码的角度来看

2. 拼接前后出现了变量
  • 如果拼接符号的前后出现了变量,则相当于在堆空间中new String()
  • 既然new了对象,那就是不同的对象,因此也就是不同的地址值
  • 对象的具体的内容是拼接的结果

3. string.intern()
  • 判断字符串常量池中是否存在“javaeehadfd”的值
  • 如果存在,则返回该常量池中该值的地址
  • 如果不存在,则在常量池中加载一份,并返回该对象的地址值
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/852013.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号