Java值、引用和对象

来源:互联网 发布:山西广电网络客服电话 编辑:程序博客网 时间:2024/06/07 18:06

概述

每种编程语言都有自己操作内存中元素的方式,有时候,程序员必须注意将要处理的数据是什么类型,是直接操纵元素,还是通过某种间接的表示来操纵对象。

在Java里面,这些操纵都得到了简化。

从数据的存储说起

首先我们必须搞清楚引用变量、值、对象在内存中是如何存储的,比如我们有如下几行代码。

int a=1;double b=1.23;object obj1=new object ();object  obj2=obj1;object  obj3=new object ();

以上代码中,我们声明了几个变量并对其设置了初始化值,但是这些变量初始化之后,编译器是如何给他们分配内存的呢?我们看下图。


这里写图片描述

在上图之中,我们可以看到,数据存储时涉及到一个栈和堆的概念。在Java中,所有的基本类型(java的基本数据类型共有8种,即int,short,long,byte,float,double,boolean,char)数据都是存储在栈中,所有非基本类型数据都是存储在堆中。

Java值、引用和对象

如上所定义的int a=1;这里的a是一个指向int类型的引用,指向1这个字面值,而int类型是基本类型,编译器先处理int a = 1;首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为1的地址,没找到,就开辟一个存放1这个字面值的地址,然后将a指向1的地址。编译器在处理基本类型时,基本都是按照这种操纵方式去处理。

我们再来看object obj1=new object ();这段代码,声明一个obj1对象时,具体步骤如下:

  1. 先在栈中为对象的应用变量obj1分配内存空间;
  2. 在堆内存中为object类的成员变量(如果有)分配内存;
  3. 初始化object类的成员变量,为成员变量赋值;
  4. 返回堆内存中对象的引用(地址)给引用变量obj1,以后就可以通过obj1来引用堆内存中的对象了。

一个类通过使用new运算符可以创建多个不同的对象实例,这些对象实例将在堆中被分配不同的内存空间,改变其中一个对象的状态不会影响其他对象的状态。比如:

object obj1=new object ();object obj3=new object ();

但是,如果有;

object obj1=new object ();object  obj2=obj1;

则在堆内存中只创建了一个对象实例,在栈内存中创建了两个对象引用,两个对象引用同时指向一个对象实例。

为什么基本数据类型要存储在栈中,而对象要存储在堆中?

堆栈:栈位于通用的RAM(随机访问存储器)中,但通过堆栈指针可以从处理器那里获得直接支持,通过堆栈指针的移动来分配和释放内存,这是一种非常快速的分配内存的方法,速度仅次于寄存器。创建程序时,Java系统必须知道存储在栈内的所有项的确切的生命周期,以便上下移动堆栈指针。这一约束限制了程序的灵活性,所以虽然某些Java数据存储于堆栈中,特别是对象引用,但是Java对象并不存储于其中。

堆:一种通用的内存池(也位于RAM区),用于存放所有的Java对象。
堆不同于堆栈的好处是:编译器不需要知道存储的数据在堆里存活多长时间。因此,在堆里分配存储有很大的灵活性。当需要一个对象时,只需用new写一行简单的代码,当执行这行代码时,会自动在堆里进行存储分配。
当然,为这种灵活性必须要付出相应的代价:用堆进行存储分配和清理可能比用栈进行内存分配需要更多的时间。

程序设计中,因为使用new关键字所创建的对象都是存储在堆中,而对于基本数据类型来说,他们都是很小、很简单的数据类型,但是使用new关键字创建很小、很简单的对象往往不是很有效。所以对于基本数据类型,不用new来创建变量,而是创建一个并非引用的“自动”变量。这个变量直接存储“值”,并置于堆栈中,因此更加高效。

原创粉丝点击