String到底在内存中是如何存储的
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
可见不是所有的自动包装机制都实现了全缓存。
String到底在内存中是如何存储的的更多相关文章
- C语言中float,double类型,在内存中的结构(存储方式)
C语言中float,double类型,在内存中的结构(存储方式)从存储结构和算法上来讲,double和float是一样的,不一样的地方仅仅是float是32位的,double是64位的,所以doubl ...
- @清晰掉 C++ 中的 enum 结构在内存中是怎么存储的?
C++ 中的 enum 结构在内存中是怎么存储的? C++ C++ 中的 enum 结构在内存中是怎么存储的?里面存储的是常量值吗? 关于占用内存的大小,enum类型本身是不占内存的,编译器直接 ...
- float数据在内存中是怎么存储的 AND IEEE754测试程序
float类型数字在计算机中用4个字节存储.遵循IEEE-754格式标准: 一个浮点数有2部分组成:底数m和指数e 底数部分 使用二进制数来表示此浮点数的实际值指数部分 占用8bit的二进制数,可表示 ...
- 代码演示C#中string和StingBuilder内存中的区别
关于 string和StringBuilder的区别参考MSDN.本文用程序演示它们在内存中的区别,及其因此其行为不同. //Demo string memory model namespace C ...
- C# CLR via 对象内存中堆的存储【类型对象指针、同步块索引】
最近在看书,看到了对象在内存中的存储方式. 讲到了对象存储在内存堆中,分配的空间除了类型对象的成员所需的内存量,还有额外的成员(类型对象指针. 同步块索引 ),看到这个我就有点不懂了,不知道类型对象指 ...
- 牛客网Java刷题知识点float数据在内存中是怎么存储的
不多说,直接上干货! float类型数字在计算机中用4个字节存储. 遵循IEEE-754格式标准: 一个浮点数有2部分组成:底数m和指数e (1)底数部分 使用二进制数来表示此浮点数的实际值 (2)指 ...
- js的数组在内存中是如何存储的
前言:本来想自己总结下,但发现以下文章已经写得很好,就直接放链接了. 英文文章:http://voidcanvas.com/javascript-array-evolution-performance ...
- Java语言中:float、double数据类型在内存中是如何存储的
引用参考 https://www.cnblogs.com/chenmingjun/p/8415464.html#4291528 https://blog.csdn.net/yansmile1/arti ...
- JavaScript中的变量在内存中的具体存储形式
栈内存和堆内存 JavaScript中的变量分为基本类型和引用类型 基本类型是保存在栈内存中的简单数据段,它们的值都有固定的大小,保存在栈空间,通过按值访问 引用类型是保存在堆内存中的对象,值大小不固 ...
随机推荐
- 备份一个支持虚拟化的wrappanel
public class VirtualizingWrapPanel : VirtualizingPanel, IScrollInfo { #region Fields UIElementCollec ...
- WPF TreeView HierarchicalDataTemplate
原文 WPF TreeView HierarchicalDataTemplate HierarchicalDataTemplate 的DataType是本层的绑定,而ItemsSource是绑定下层的 ...
- C# 事件详解
1.事件的本质是什么 答:事件是委托的包装器,就像属性是字段的包装器一样 2.为什么有了委托还有有事件 委托可以被访问就可以被执行,事件则只能在类的内部执行 3.事件要怎么声明 a.明一个委托 //委 ...
- VS生成Cordova for Android应用之Gradle
原文:VS生成Cordova for Android应用之Gradle 一.Gradle简介 Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化建构工具.它使用一种基 ...
- 使用sklearn构建含有标量属性的决策树
网络上使用sklearn生成决策树的资料很多,这里主要说明遇见标量数据的处理. 经查验参考资料,sklearn并非使用了课上以及书上讲的ID3算法,而是选择了CART,该算法生成二叉树:scikit- ...
- Python中实现switch分支结构
Python不像C/C++,Java等有switch-case的语法.不过其这个功能,比如用Dictionary以及lambda匿名函数特性来替代实现. 实现方法分为两步: 首先,定义一个字典: 其次 ...
- 如何替换Windows的Shell(即explorer.exe)
原文:如何替换Windows的Shell(即explorer.exe) 下载一个可以查看用户的SID的软件,如SysInternals套装中的PsGetsid.exe(地址:http://www.it ...
- Delphi编程中Http协议应用
Http协议的通信遵循一定的约定.例如,请求一个文件的时候先发送Get请求,然后服务器会返回请求的数据.如果需要进行断点传输,那么先发送'HEAD /'请求,其中返回的'Content-Length: ...
- delphi中pos和Ansipos函数的区别
POS和ANSIPOS的主要区别在于,POS参数多用于是一个字符,而ANSIPOS多用于是多个字符: 例如:i:=pos('a','sssssas'); i:=ansipos('abc','sdabc ...
- Java基础(二) 基本类型数据类型、包装类及自动拆装箱
我们知道基本数据类型包括byte, short, int, long, float, double, char, boolean,对应的包装类分别是Byte, Short, Integer, Long ...