美文网首页
Java的存储

Java的存储

作者: liuzhifeng | 来源:发表于2017-10-14 12:18 被阅读0次

程序运行时,有6个地方可以保存数据:

  • 寄存器
  • 堆栈
  • 静态存储
  • 常数存储
  • 非RAM存储

寄存器

寄存器位于处理器内部,是运行速度最快的保存区域。由于寄存器的数量有限,只能根据需要由编译器进行分配,我们对寄存器的分配没有直接的控制权。

堆栈

堆栈驻留于常规RAM(随机访问存储器)区域,可以通过堆栈指针获得处理的直接支持。堆栈指针下移则创建新的内存,上移则释放内存。
堆栈存储的速率仅次于寄存器。创建程序时,Java编译器必须准确地知道堆栈内保存的所有数据的长度与存在时间,从而生成相应的代码,以便向上和向下移动指针。
基本数据类型(int, short, long, byte, float, double, boolean, char)、对象句柄需要保存在堆栈中。但对象不在其中。

顺便提一下,Java中认为“所有一切皆对象”,但实际操纵的标识符是一个指向对象的句柄,相当于引用、指针。Java编程思想中举了一个生动的例子:将对象看成“电视机”,句柄则为操纵电视机的“遥控器”。实际上我们操纵的是遥控器,再通过遥控器改变电视机的状态。此外,没有电视机,遥控器依然可以存在。这说明拥有一个句柄并不表示必须有一个对象同它连接
对于基本数据类型,如:

        int a = 1;

仅仅是产生了一个int句柄(应用),指向存储数据1的栈,而没有生成对象。
堆栈中的数据可以共享。如:

        int a = 3;
        int b = 3;

这里,首先创建int型的句柄a,需要指向面值为3的栈地址。如果没有找到,堆栈指针下移新开辟一个栈地址存储3,a就指向这个地址;接着创建b时,在堆栈中找到了相同的面值3,直接让b指向3对应的栈地址即可。

注意,字面值的引用与类对象的引用不同。假定两个类对象的引用同时指向一个对象,如果一个对象引用变量修改了这个对象的内部状态,那么另一个对 象引用变量也即刻反映出这个变化。相反,通过字面值的引用来修改其值,不会导致另一个指向此字面值的引用的值也跟着改变的情况。

再看一个例子:

String s;

这里我们创建了一个String句柄s,注意这只是句柄而不是对象。若此时向s发送消息,会产生错误,这是因为s实际上并未与任何对象连接(即没有“电视机”)。那么创建句柄时,我们希望它同一个新的对象连接。通常用new关键字达到这一目的。如:

        String s = new String("asdf") 

我们再来看看new,新建对象的存储方式。

堆是一种常规用途的内存池(也在RAM区域),其中保存了Java的对象。要求创建新对象时,只需要用new命令即可。执行这些代码时,会在堆里自动生成数据的保存。
堆最吸引人的地方在于编译器并不需要考虑堆需要分配多少的空间、保存多少的时间,具有更大的灵活性。然而,缺点在于,在堆里分配存储空间会用掉更长的时间。
堆中同时保存了包装数据类型(Integer, String, Double等)。包装数据类型将相应的基本数据类型包装起来的类。这些类数据全部存在于堆中,Java用new()语句来显示地告诉编译器,在运行时才根据需要动态创建。

来看一个例子:

        Integer a = 3;
        Integer b = 3;
        System.out.println(a == b); (1)

        Integer c = 321;
        Integer d = 321;
        System.out.println(c == d); (2)

这里新建了4个对象a、b、c、d,判断他们是否相等。结果为:(1)true,(2)false
为什么会这样呢?
其实,在从int到Integer做封装时,是有规则的。系统已经默认把-128到127之间的Integer缓存到一个Integer数组存储在堆中了。当我们要从把一个int转化为Integer时,首先会在缓存中查找:
  如果找到,就直接返回引用,不必新new一个,即a和b是同一个面值为3的引用,所以a==b。
  否则,对于不在缓存中的数据,需要新new一个,因此c和d并没有指向同一个对象,只不过是c和d的对象对应的值相同,地址是不同的。所以c!=d


到这里,我们来观察一下两种新建方式:

        String str = "abcd";  (1)
        String str = new String("abcd"); (2)

String是一种特殊的包装类数据,拥有上述两种初始化方式。分别来分析:
(1)代表,我们创建了String类的句柄str,但并不一定是创建了String类的对象。str是否指向一个String类的对象,需要由上下文来确定:
  首先,堆栈新开辟地址,存储句柄str。查找常量池中是否存在内容为"abcd"的对象;
  如果有,则堆栈中的句柄str直接指向该对象,即成为该对象的引用;
  如果没有,则在常量池中创建对象,值为"abcd",并让str指向该对象。

(2)代表创建了String类的句柄,并将其指向一个堆中的对象:
  首先,在中创建一个对象,值为"abcd",并让str指向该对象;
  接着,在常量池中查看,是否存在值为"abcd"的对象
  若存在,则将new出来的字符串对象与字符串常量池中的对象联系起来;
  若不存在,则在字符串常量池中新建对象,值为"abcd",并将new出来的字符串对象与字符串常量池中的对象联系起来
可以使用inturn方法返回该字符串在常量池中的引用

通过上述的分析,可以解决一道面试题:

        String s = new String("China")产生几个对象?

答案是1或2。如果常量池中已经存在值为“China”的对象,就产生1个;否则产生2个。

当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率

再看一个例子:

        String str1 = "abc"; 
        String str2 = "ab" + "c";
        System.out.println(str1 == str2);  (1)

        String str3 = "ab"; 
        String str4 = str3 + "c";
        System.out.println(str3 == str4);  (2)

这里,(1)的结果为true,因为str1句柄会在字符串常量池中创建内容为"abc"的对象;str2为两个常量相加,结果也为"abc",同样指向字符串常量池中的对象,因此两个引用相同;

而(2)的结果为false,因为str4=str3+"c"涉及到变量的相加,会新建一个对象(先new一个StringBuilder,然后 append(str2),append("c");然后让str3引用toString()返回的对象)。

更多有关String的例子,可以钻研:Java堆、栈和常量池以及相关String的详细讲解
关于其他包装数据类型和常量池相关的操作,可以参考:Java常量池理解与总结-简书


静态存储

所谓静态存储(static)是指“位于固定位置”,也存在于RAM中。程序运行过程中,静态存储的数据将随时等候调用。static类型的数据被所有对象所共享。

常数存储

常数值通常直接置于程序代码内部,因为它们永远都不会改变,所以是安全的。有的常数需要严格地保护,所以可考虑将它们置入只读存储器ROM。(public static final)

非RAM存储

非RAM存储的数据可以位于其他媒体中,在程序不再运行时仍可存在,并在程序的控制范围之外。如磁盘、硬盘等。

相关文章

  • ThreadLocal的简单了解

    存储结构Thread对象中会存储属性java.lang.Thread.threadLocals,它的类型是java...

  • Java的存储

    程序运行时,有6个地方可以保存数据: 寄存器 堆栈 堆 静态存储 常数存储 非RAM存储 寄存器 寄存器位于处理器...

  • java中如何调用存储过程

    java中如何调用存储过程 Java如何实现对存储过程的调用: 1、不带输出参数的 create procedur...

  • Java调用存储过程

    Java调用存储过程 调用存储过程 调用存储函数 cursor作为out参数返回

  • 2019Android面试总结

    [TODO] 存储方式网络存储 Java equals和==、hashCode的区别 == 比较栈中存储的值是否...

  • java面试要点

    JAVA java 中char 类型不存储UTF-8 而是存储UTF-16在java中char 占用两个字节 UT...

  • Java基础提升4

    本文将阐述关于Java语言中变量是如何存储的。 Java中数据的存储位置 寄存器 最快的存储区,位于处理器的内部,...

  • 深入理解Java Runtime Area Java运行时数据区

    Java Runtime Area的分类从线程的角度理解Java Runtime Area从存储内容理解Java ...

  • 模拟分页存储算法Java版

    分页存储管理算法 Java 版

  • 2018-04-17

    Java集合 ★★★★★集合框架:用于存储数据的容器。 特点: 1:对象封装数据,对象多了也需要存储。集合用于存储...

网友评论

      本文标题:Java的存储

      本文链接:https://www.haomeiwen.com/subject/dlsxuxtx.html