博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
String到底在内存中是如何存储的
阅读量:6811 次
发布时间:2019-06-26

本文共 2854 字,大约阅读时间需要 9 分钟。

String会出现在哪些地方

  • 方法内的局部string
  • 类内的字段String
  • static string
  • 容器中存储的string
  • String数组
    那么String的位置会影响其存储方式吗?
    显然是不会的,类永远只会储存在堆上。
    但是实际上类的字段并不是一直在堆上的。

String的构造方法

以下来自String类 源码,一些无关紧要的实现被我省略了:

private final char value[];    private int hash; // Default to 0    private static final long serialVersionUID = -6849794470754667710L;    private static final ObjectStreamField[] serialPersistentFields =        new ObjectStreamField[0];   public String() {        this.value = "".value;    }  public String(String original) {        this.value = original.value;//底层char[]指向了同一位置!        this.hash = original.hash;    }    public String(char value[]) {        this.value = Arrays.copyOf(value, value.length);//底层char[]指向不同位置!下面的截取也是如此    }    public String(char value[], int offset, int count) { ... }    public String(int[] codePoints, int offset, int count) {...}    public String(byte ascii[], int hibyte, int offset, int count) {...}    public String(byte ascii[], int hibyte) {...}

我们可以发现String的构造器并不关注是否将char[]指向同一位置,之所以有一些没有指向同一位置完全是为了保证char[]是immutable的。

这并不能说明调用构造器构造的String的内存位置有什么特别之处。

String另一种构造方式--为包装类型提供的专有构造方式

运行如下代码:

class StringPointerTest{    String g="gh",h="gh";}public class StringTest {    public static void main(String[] args) {        String a="abc";        String b="abc";        System.out.println(a==b);//true使用简写的构造能够复用创建的string类        String c=new String("abc");        System.out.println(a==c);//false是用构造器则不能        String d=new String("def");        String e="def";        System.out.println(d==e);//false即使先构造器再使用简化构造也不行。        StringPointerTest spt=new StringPointerTest();        System.out.println(spt.g==spt.h); //true与String的属于方法局部变量还是类字段也无关    }}
class IntegerPointTest1{    Integer a=1;}class IntegerPointTest2{    Integer b=1;}public class IntegerTest {    public static void main(String[] args) {       System.out.println(new IntegerPointTest1().a==new IntegerPointTest2().b);//true!    }}

原理

需要存储的代码元素有:

  • Class类文件
  • 方法,类的所以实例应该共用一段方法
  • static字段
  • 字符串常量
  • 值常量
  • 类实例
  • 各种引用
  • 基本变量
    他们各自有各自的存储位置,方法内的引用存在方法栈,类内的引用存在堆,类存储在堆上,方法中的局部基本变量存于栈但是类字段的基本变量存在堆上(方法区内)。
    值得一提的是方法区(又叫静态区),其存储值常量、字符串常量、方法、静态字段、.class文件,等只用一个备份的数据。
    栈和方法区都有共享数据的功能。
    因此使用简化方法构造String类的时候,在方法内和类内会将字符串存于栈/方法区,这无关紧要,重要的是,
    使用这种构造方法,如果没有所构造的字符串常量存在于内存中,那么会在栈/方法区中存上一份,然后再堆中新建一个String类,把String类的char[]引用指向在栈/方法区中的字符串常量;
    如果所构造的字符串常量已经存在于内存中,那么则会检索关联与之对应的堆中String实例,并直接使用这个String类实例。
    只有使用简化方法构造才能被栈/方法区记录下来,如果使用new则不行,这也是为什么上例即使先new,再使用简化构造相同字符串也不会引用相同。
    因为new出来的String实例的字符串常量存储在堆上,和栈/方法区无关。

拓展到所有包装类型---可以吗?

完全不可以。

他们都没有像String那样实现缓存。
但是实现了类似的缓存,它们的自动包装机制也提供缓存功能,
但是是基于valueof方法的,该方法会对一定范围内进行缓存。
而且实现方式非常暴力,是在对应类里存一个静态的类数组,并静态初始化全部填充。

可以缓存的范围:

byte Byte -128–127
short Short -128–127
int Integer -128—127
long Long -128—127
char Character 0–127
boolean Boolean TURE,FALSE
String
不缓存的:
float Float
double Double

可见不是所有的自动包装机制都实现了全缓存。

转载于:https://www.cnblogs.com/gjl-blog/p/8600738.html

你可能感兴趣的文章
新计算,新纪元——2017 Kubertenes Meetup 即将开幕!
查看>>
【操作系统】3、存储管理
查看>>
咪咕视讯王斌:5G时代的泛娱乐产业生长
查看>>
VC中的正则表达式使用
查看>>
3PAR公司推出第三代虚拟存储阵列
查看>>
对待棘手bug,新手与大牛的差距在哪里?
查看>>
中企通信发布DaaS桌面云解决方案 企业迎来真正“桌面即服务”
查看>>
英国风力发电已比核能便宜
查看>>
《并行计算的编程模型》一2.6.3 AM Ping-Pong示例
查看>>
Kronos银行木马的前世今生
查看>>
武汉电博会看点 daydao电商云ERP亮相
查看>>
浪潮李辉:SDS,承载应用和技术两极蔓延式创新
查看>>
机会与危险并存 存储业希望依旧
查看>>
GE以9.15亿美元收购ServiceMax 以完善工业互联网平台
查看>>
Windows Shellcode学习笔记——通过VirtualProtect绕过DEP
查看>>
Apache httpd 出现多个漏洞 可能引发DoS攻击 2.2.x及2.4.x版本受影响
查看>>
ARM计划将四核心CPU引入磁盘驱动器
查看>>
智慧城市数量年内超500个 这两大难题不得不解
查看>>
《中国人工智能学会通讯》——10.27 提出的方法
查看>>
大数据重点不在于“大”
查看>>