java 引用数据类型变量
在这篇文章中,它描述了面向对象编程的一个重要概念:每个类实例,对象只由引用类型变量管理(对于那些也知道C++的人,你可以记住C++中的这个规则并不完全正确,因为对象也由值类型变量管理)。
这个规则对于理解是非常重要的,因为它是定义面向对象编程语言(C# )的一个基本事实。理解它,将理解和学习Java编程。
什么是引用数据类型变量
引用变量,或者说引用(Reference),是变量(就像一个原始数据类型,比如int vb),因为它们需要内存空间来存储它们的值。引用变量和基元数据类型变量之间的主要区别在于,第一个变量的值是表示堆中内存区域的地址(主要是地址)的数字。
当进程启动(应用程序)时,它需要活动内存(随机访问内存)来存储数据、代码和堆栈(一个固定的临时缓冲区,供将来使用)。JVM(Java虚拟机)根据运行前(基于源代码中定义的变量)和应用程序执行期间可以确定的内容为其保留内存空间。
因此,该进程管理并需要两个数据存储区:
stack栈——固定大小的栈;它的大小是根据函数执行前可用的信息来确定的(记住,最简单的Java应用程序需要一个函数——main);这个信息是由函数局部变量和输入变量(对于main,其局部变量实际上是应用变量;
Heap堆——动态的,它表示运行时需要或不需要的数据的内存需求;你不确定你是否需要它,以及它的大小,因为它取决于应用程序的执行和其他外部输入(假设我们有一个应用程序记录数组的值,但是它的大小和值是由用户在运行时给定的;因此我们知道应用程序将需要一些额外的内存空间,但我们不知道有多少字节,因为我们不知道用户将插入什么);为了保留这个空间,在运行时,我们将使用new运算符或函数;堆也称为动态管理的内存,因为它响应来自不同进程的内存请求,并在不再需要时释放使用过的内存。
下面是一个生成数组的示例,该数组的长度由用户在运行时给定:
try { int[] intValues; int num = 0; System.out.println("请输入数组大小 (0 - 255):"); // 输入数组值 num = System.in.read(); intValues = new int[num]; // 打印数组值 - 默认全部是0 for(int i=0; i < intValues.length; i++) System.out.print(" "+intValues[i]); } catch(IOException ex){ System.out.println(ex.getMessage()); }
关于变量在内存中的位置的一般规则是:
在函数块中声明的变量(在Java中不能像C或C++那样声明全局变量,)或参数列表中的变量被放置在堆栈(函数栈)上;
使用new运算符创建的任何值都将放在堆中。
不要忘记在Java中,任何数组都是一个对象。数组引用在栈上,其值在堆中
如何定义引用数据类型变量
定义引用的语法为:
class_name reference_name;
每次定义引用时,如果它不是本地变量(默认值为没有地址的预定义值),则它的默认值等于*NULL**;在C/C++中,空值等于0。这意味着它不能被使用。
如果引用是一个局部变量(而不是实例变量-属性),那么我们将收到一个编译器错误。
如果我们考虑这个类
class Auto{ int maxSpeed; float weight; int noSeats; }
然后测试它,我们会得到一个 变量auto可能没有初始化 (variable auto might not have been initialized)编译器错误,如果我们尝试这个
public class TestAuto { public static void main(String[] args) { //定义局部变量/引用 // 局部变量没有使用缺省值进行初始化 Auto auto; //编译错误 auto.maxSpeed = 160; } }
将运行时异常 java.lang.NullPointerException(因为对象不存在,并且没有存储160值的内存空间):
如何初始化引用数据类型变量
所有引用都是以地址(数字)作为值的变量。为了得到一个地址,我们必须请求并在堆中保留一些内存(仅在这里)。使用 new运算符完成此操作,如下所示:
reference_type reference=new reference_type(); // 如果是对象 base_type array_reference= new base_type[elements_number]; // 如果是数组
如果我们考虑这个Java示例:
public class TestAuto { public static void main(String[] args) { //定义一个Auto引用 // 进行初始化 Auto auto = new Auto(); //初始化对象值 auto.maxSpeed = 160; auto.noSeats = 5; auto.weight = 1500; //定义并初始化数组引用 int[] someInts = new int[3]; someInts[0] = 10; someInts[1] = 20; someInts[2] = 30; } }
那么它在内存中看起来是这样的:
对象值及其引用的内存映像
注意当我们在两个引用之间使用=(相等)时,右引用的值将复制到左引用中。重要的是要理解复制的是引用值,而不是堆中的对象或数组值。这种类型的拷贝称为 浅拷贝。
例如,如果我们在初始情况中添加一些指令(前一个示例)
Auto newAuto = auto; int[] otherInts = someInts;
由两个引用管理的对象值
在内存中,主函数栈上有4个引用,堆中只有2个值(一个对象和一个数组)。在这种情况下,我们可以通过具有相同值的两个不同引用访问对象值: