当前位置: 首页>编程语言>正文

java 数据迁移后 如何验证数据的正确性 java数据传递方式

本文通过内存模型的方式来讨论一下Java中的參数传递。

1、基本类型參数的传递方式

这里的内存模型涉及到两种类型的内存:栈内存(stack)和堆内存(heap)。基本类型作为參数传递时,传递的是这个值的拷贝。

不管你怎么改变这个拷贝,原值是不会改变的。

看下边的一段代码,然后结合内存模型来说明问题:

public class ParameterTransfer {
 public static void main(String[] args) {
  int num = 30;
  System.out.println("调用add方法前num=" + num);
  add(num);
  System.out.println("调用add方法后num=" + num);
 }
 
 public static void add(int param) {
  param = 100;
 }
 
}

这段代码执行的结果例如以下:

调用add方法前num=30
 调用add方法后num=30

程序执行的结果也说明这一点,不管你在add()方法中怎么改变參数param的值,原值num都不会改变。
下边通过内存模型来分析一下。
当运行了int num = 30;这句代码后,程序在栈内存中开辟了一块地址为AD8500的内存,里边放的值是30,内存模型例如以下图:

java 数据迁移后 如何验证数据的正确性 java数据传递方式,java 数据迁移后 如何验证数据的正确性 java数据传递方式_堆内存,第1张

 运行到add()方法时,程序在栈内存中又开辟了一块地址为AD8600的内存,将num的值30传递进来,此时这块内存里边放的值是30。运行param = 100;后,AD8600中的值变成了100。内存模型例如以下图:   

java 数据迁移后 如何验证数据的正确性 java数据传递方式,java 数据迁移后 如何验证数据的正确性 java数据传递方式_内存模型_02,第2张

地址AD8600中用于存放param的值,和存放num的内存没有不论什么关系,不管你怎么改变param的值,实际改变的是地址为AD8600的内存中的值,而AD8500中的值并未改变,所以num的值也就没有改变。

2、对象类型參数的传递方式

1)先看下边的演示样例代码:

public class ParameterTransfer {
 public static void main(String[] args) {
  String[] array = new String[] {"huixin"};
  System.out.println("调用reset方法前array中的第0个元素的值是:" + array[0]);
  reset(array);
  System.out.println("调用reset方法后array中的第0个元素的值是:" + array[0]);
 }
 
 public static void reset(String[] param) {
  param[0] = "hello, world!";
 }
 
}

执行的结果例如以下:

调用reset方法前array中的第0个元素的值是:huixin

调用reset方法后array中的第0个元素的值是:hello, world!

当对象作为參数传递时,传递的是对象的引用,也就是对象的地址。下边用内存模型图来说明。


java 数据迁移后 如何验证数据的正确性 java数据传递方式,java 数据迁移后 如何验证数据的正确性 java数据传递方式_栈内存_03,第3张

当程序运行了String[] array = new String[] {"huixin"}后。程序在栈内存中开辟了一块地址编号为AD9500内存空间,用于存放array[0]的引用地址。里边放的值是堆内存中的一个地址。演示样例中的值为BE2500,能够理解为有一个指针指向了堆内存中的编号为BE2500的地址。堆内存中编号为BE2500的这个地址中存放的才是array[0]的值:huixin。
当程序进入reset方法后。将array的值,也就是对象的引用BE2500传了进来。这时,程序在栈内存中又开辟了一块编号为AD9600的内存空间,里边放的值是传递过来的值。即AD9600。

能够理解为栈内存中的编号为AD9600的内存中有一个指针,也指向了堆内存中编号为BE2500的内存地址,如图所看到的:

java 数据迁移后 如何验证数据的正确性 java数据传递方式,java 数据迁移后 如何验证数据的正确性 java数据传递方式_堆内存_04,第4张

这样一来,栈内存AD9500和AD9600(即array[0]和param的值)都指向了编号为BE2500的堆内存。

在reset方法中将param的值改动为hello, world!后,内存模型例如以下图所看到的:

java 数据迁移后 如何验证数据的正确性 java数据传递方式,java 数据迁移后 如何验证数据的正确性 java数据传递方式_堆内存_05,第5张

改变对象param的值实际上是改变param这个栈内存所指向的堆内存中的值。param这个对象在栈内存中的地址是AD9600,里边存放的值是BE2500。所以堆内存BE2500中的值就变成了hello,world!。程序放回main方法之后,堆内存BE2500中的值仍然为hello,world!,main方法中array[0]的值时,从栈内存中找到array[0]的值是BE2500。然后去堆内存中找编号为BE2500的内存,里边的值是hello,world!。

所以main方法中打印出来的值就变成了hello,world!

2)我们再来看个样例

class Dog{
	int x,y;
	int z=1;
	Dog(int x,int y){
		this.x=x;
		this.y=y;
	}
	void move1(Dog d){
		d.x=d.x+10;
		d.y=d.y+10;
	}
	void move2(Dog d){
		Dog d2=new Dog(100, 100);
		d=d2;
		
	}
}
public class UseDog {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Dog d1=new Dog(10,10);
		d1.move2(d1);
		System.out.print(d1.x+","+d1.y+":");
		d1.move1(d1);
		System.out.println(d1.x+","+d1.y+";");
	}

}

输出结果为:10,10:20,20;

先解释10,10:当运行d1.move2(d1)时。d1(引用地址)传入move2中,栈内存开辟空间存入。之后新建对象d2,并将d2(引用地址)赋给d,那么d就指向了对象d2。因此并未改变d1所指向的堆内存值。

再解释20,20:当运行d1.move1(d1)时,d1(引用地址)传入move1中,栈内存开辟空间存入,即d指向了d1所指向的堆内存值。这时在move1中改变d所指向的对象的值,那么d1所指向的对象值也改变了。由于d和d1指向的是同一个对象。

3、总结

不管是基本类型作为參数传递,还是对象作为參数传递,实际上传递的都是值,仅仅是值的的形式不用而已。

第一个演示样例中用基本类型作为參数传递时。将栈内存中的值30传递到了add方法中。

第二个演示样例中用对象作为參数传递时,将栈内存中的值BE2500传递到了reset方法中。当用对象作为參数传递时。真正的值是放在堆内存中的。传递的是栈内存中的值。而栈内存中存放的是堆内存的地址,所以传递的就是堆内存的地址。这就是它们的差别。

补充一下,在Java中,String是一个引用类型,可是在作为參数传递的时候表现出来的却是基本类型的特性。即在方法中改变了String类型的变量的值后,不会影响方法外的String变量的值。


https://www.xamrdz.com/lan/5cz1963190.html

相关文章: