java函数中值传参和对象传参的区别
java中基本类型和类对象存储的过程
书面描述:
在java内存中定义一个变量时会先开辟一个空间,来存储这个变量。不同的是,当变量为基本类型时,存储的空间会直接存储对应的数值。而当变量(或者应该称为对象)为某一个类时,该空间只是存储一个内存地址,而该地址指向变量对应的类实例。
代码测验:
1.函数传参为对象时
比如有一个方法test(A a),当A类对象b作为参数传入test()方法中时,对象b会随着函数中a的变化而变化。即为引用传递。
伪代码如下:
测试方法代码块:
{
定义类对象 A b = new A();
b.name = 0;
输出b.name
test(b);
输出b.name
}
方法 test():
test (A a){
a.name = 12;
输出 a.name
}
在传参时,如果传参为基本类型的话为值传参,不会发生任何变化。
而如果传递参数为对象时,此时为引用传参。在函数中参数所做的改变也是被传参的变量所做的改变。
例子如下:
//这是测试用到的自定义类 Cat
public class Cat {
private String sound = null;
private String jump = null;
public String getSound() {
return sound;
}
public void setSound(String sound) {
this.sound = sound;
}
public String getJump() {
return jump;
}
public void setJump(String jump) {
this.jump = jump;
}
@Override
public String toString() {
return "Cat{" +
"sound='" + sound + '\'' +
", jump='" + jump + '\'' +
'}';
}
}
//这是测试的代码块
public static void main (String[] args) {
Cat cat = new Cat();
System.out.print("这是初始定义的类对象:");
System.out.println(cat);
test(cat);
System.out.print("这是传参之后的的类对象:");
System.out.println(cat);
}
public static void test(Cat cat){
cat.setJump("Very high");
cat.setSound("Cute yet disturbing");
System.out.print("这是方法中输出的类对象:");
System.out.println(cat);
}
输出结果如下:
这是初始定义的类对象:Cat{sound='null', jump='null'}
这是方法中输出的类对象:Cat{sound='Cute yet disturbing', jump='Very high'}
这是传参之后的的类对象:Cat{sound='Cute yet disturbing', jump='Very high'}
Process finished with exit code 0
以上是函数传参时对象发生的变化。
而String类则不同,它不会改变
@Test
public void testString() {
String name = null;
System.out.println("初始化后的String为:" + name);
transferString(name);
System.out.println("传参后的String为:" + name);
}
public void transferString(String data) {
data = "Hahahahaha";
System.out.println("修改后的String为:" + data);
}
输出结果如下:
初始化后的String为:null
修改后的String为:Hahahahaha
传参后的String为:null
其实不仅仅是函数传参,在同一个方法中类的传递也同样如此。代码如下:
@Test
public void testSameClass() {
Cat littileOne = new Cat();
System.out.println("之前的喵喵是:" + littileOne);
Cat second = littileOne;
second.setSound("miao~~~~~?");
second.setJump("Low");
System.out.println("第二只喵喵是:" + second);
System.out.println("之前的喵喵是:" + littileOne);
}
结果如下:
之前的喵喵是:Cat{sound='null', jump='null'}
第二只喵喵是:Cat{sound='miao~~~~~?', jump='Low'}
之前的喵喵是:Cat{sound='miao~~~~~?', jump='Low'}
小结:
1.在java中除String类外,基本类型变量的传递都是值传递,而自定义类或者java中的工具类的对象传递都是引用传递。关于String类为什么这么秀,还要关系到java中内存空间的问题。因为笔者描述能力有限(实在是不知道怎么说,而且正在画图中),只能在下一篇博客中讲清楚。
2.1个人对变量和对象存储的理解:
除了long和double两个64位长度的类型数据占用两个变量存储空间,其他的java基本类型变量或对象所占的存储空间都是一样的,只占一个存储空间。可以这么想象,公司给两个员工各发了一套二十平的房子,员工A(代表基本类型变量)单身一人,很高兴的把所有东西都搬了进去,空间正合适。而员工B(代表对象引用)一大家子人,住得远,根本没地方,只能自己搬过来住。那么当公司需要拿户口本(代表变量的所有信息)的时候,A直接回去拿就可以了,而B要回公司发的房子拿家门钥匙,再回家一趟才能拿到。
具体的细节忽略的话,其实可以得出一个结论,造成值传递和引用传递的现象是对象存储数据的数量不同。基本类型对应的实例称为变量。一个基本类型int变量存储数据最大的也只是2的31次方大小,但这只能存储一个固定类型数据。而java允许存在或定义特殊的类型变量,通过把对应的某些不同类型的多个数据存储到一个**“大的类型”中**,并设置对应的操作这些数据的方法,不但可以获取更多的数据,也可以通过这单个变量对数据进行操作得到我们想要的结果。而这个“大的类型”在Java中称为类。而类所对应的实例称为对象。这也可以侧面证明java中认为一切皆是对象的理念之优秀。
2.2抬杠时间&反思时间:
杠精:我只定义一个类,其中只含有一个变量可不可以能直接用一个单位存储呢?
public class A(){
int a = 0;
}
首先这存储的信息有两个,类名A,A中的变量名,所以是不行的。
———————————————————————————我是分割线————————————————————————————
杠精:那照你说的我只定义一个空类可以吗?
public class A(){
}
首先这是不行的,也是不适用的。一个空类和一个基本类型没什么区别,甚至这个空类并不能存储数据。它更像是一个接口。具体接口的用处可以看看我的博客java接口interface的存在意义浅谈。并且还存在这样一个实现序列化的空接口Serializable,大家有兴趣的可以找找源码看看对应的注释。最重要的是java中所有的类都是Object类的子类,其中有一系列的方法。