最近新学JAVA,对其中“没有指针”这一项很感兴趣。
在C++中,指针变量的声明和初始化: int *ptr ; ptr = new int();
ptr是一个指针,在堆内存中由new操作开辟一块空间,将空间的首地址返回给ptr,也就是说,ptr的值是一个内存地址。而该地址内存里面存储的数据是int类型的,通过ptr可以获取具体数值。由此可见,指针变量本身是一个地址,而该地址所指向的内存里面的数据是由指针类型来确定的,通过“”符号来获取。
在C++中,指针的赋值: (1)ptr= &i; (2) *ptr = 5;。(1)语句是使得ptr指针引用i变量的内存,也就是说,此时,ptr在内存中的地址和i在内存中地址是一样的,i改变,ptr也跟着改变。(2)语句是在ptr指针已经声明并有了地址之后才有效的,直接将5放到ptr指针指向的地址内存里面。在这里,“&”符号表示引用内存空间。
但是,在JAVA中是没有用“*”符号来声明指针的,但是想实现在C++指针一样的功效,该怎么办呢?
在JAVA中,数据类型分为基本数据类型和引用数据类型,基本数据类型是指数值型、字符型和布尔型共8中类型,重点是引用型包括类、接口和数组。引用型数据的声明和初始化跟指针很像,比如: 先定义了一个类A,现在在main函数里面创建一个Person类的对象,Person a= new Person(); 同理,new操作在堆内存里面开辟一块空间,将内存空间的首地址返回给对象a,而对象a所指向的地址内存里面的数值就是Person类定义的属性(年龄,姓名等)。
函数对数值参数的传递和引用参数的传递是不一样的。代码如下图。
输出的结果是:
为什么在使用change函数的前后,A和x的值一个改变一个不改变呢?为什么B的值在使用change函数的前后都不变呢?下面介绍的原理在C++和JAVA编程里面都是一样的。
对于第一个问题,函数在处理一个是局部变量且数值型数据的参数x的时候,会先拷贝一份main里面的x变量,得x1,将原来的x作为备份,而只处理有着相同类型和值得变量x1,在函数处理完后,这个x1会直接消亡掉。因此,函数并没有直接处理变量x。在调用change函数中,x1从10变成了20,而作为备份的x仍然是10,没有改变。如果想要输出x =20,则需要在change函数里面加上输出语句,输出x1的值。若x是一个全局变量,并且在change函数里面直接使用如 change(A a) { x = 20; a.str = "z"; },由于全局变量的生存期是整个文件的生存期,则在main中,使用change函数前后,x变量从10变成了20。
对于A类型的引用参数a,change函数中引用的是a的地址,也就是说change函数的参数a与main定义的对象a所引用的内存地址是一样的,因此,参数a一旦改变,main中的a对象也会随之改变。
然而,对于第2个问题,对象b实现的是保存对象a原状态的功能。在A类的定义中,有A(A old)构造函数,创建b对象时通过new操作重新开辟了一块内存空间,并将a的属性值全部存储下来,因此对象a和对象b引用的是不同的内存地址,对象a的改变不会影响对象b。 但如果想要对象b随着对象a一起变化,则需要如main中注释的那样声明对象b并赋值:
A b = a;
A b = new A(); b=a;
第一句是将对象b直接引用对象a的内存空间,是引用传递。第二句先利用A()默认构造函数(在有其他构造函数的情况下,要引用默认构造函数,A类里面必须出现该默认构造函数)新建内存空间,再引用对象a的内存空间。
JAVA中有一中特殊情况JAVA池,将以后再介绍。