【Java的值传递机制】娓娓道来_大白话回顾Java的值传递机制(栈与堆)

        在学习Java的过程中感觉Java的值传递机制这部分有点绕,所以这篇文章来捋一捋Java的值传递机制,也非常适合像我一样的初学者来理解和学习。

        首先先回顾下关于基本数据类型变量的赋值,对于交换两个变量的值的操作,有如下代码:

public class ValueTransferTest {
	public static void main(String[] args) {
		System.out.println("*******基本数据类型**********");
		int m = 10;
		int n = m;
		System.out.println("m =" + m + ",n =" + n);  //输出结果:10,10
		
		n = 20;
		System.out.println("m =" + m + ",n =" + n);  //输出结果:10,20
    }
}

         这个结果很容易理解,因为int n = m;相当于将m所保存的值10又复制了一份给n,m和n所保存的值虽然都是10,但两个10是独立的。总结起来就是:如果变量是基本数据类型,此时赋值的是变量所保存的数据值

        那么对于引用数据类型的赋值,有如下代码示例:

public class ValueTransferTest {
	public static void main(String[] args) {
        System.out.println("*******引用数据类型**********");
		
		Order o1 = new Order();
		
		o1.orderId = 1001;
		Order o2 = o1;  //o1和o2的地址值相同,都指向堆空间中同一个对象实体
		System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId =" + o2.orderId);		
	}
}

class Order{
	int orderId;
}

        这个结果也很好理解,由于o2不是new出来的对象,所以o1与o2指向的都是对空间中的同一个对象实体,所以如果o1.orderId的值变化的话,二者都会跟着变化。 总结起来就是变量是引用数据类型时,此时赋值的时变量所保存的数据的地址值。   

        那么对于方法的形参,当形参是基本数据类型时,通过如下代码理解方法的值传递机制。比如定义一个交换两个变量的值的方法:

public class ValueTransferTest1 {
	public static void main(String[] args) {
		//交换两个变量的值的操作
		int m = 10;
		int n = 20;
		System.out.println("m =" + m + ",n =" + n);

		
		ValueTransferTest1 test = new ValueTransferTest1();
		test.swap(m, n);   //发现交换完还是m=10,n=20.
		
		System.out.println("m =" + m + ",n =" + n);
		
		
	}
	
	
	//交换两个变量值的方法
	public void swap(int m,int n) {
		int temp = m;
		m = n;
		n = temp;
	}
}

          诶,这个时候会发现调用这个方法完事儿m和n的值并没有交换,我们可以通过如下的图来理解其原因。

         上述代码实际上是将m和n两个实参的赋给了swap方法中的形参m和n,因此同上述基本数据类型的赋值一样,也是复制了10和20这两个值给swap方法中的形参,所以当swap方法执行完毕后,其方法体内的m和n是换了,然后这些局部变量就出栈了,但是!!main()方法中的m和n压根就没动!!,你换的是也可以说是m和n的替身,所以造成上述结果。那么如何实现真正交换main方法中m和n的值的方法呢?代码如下:

public class ValueTransferTest2 {
	public static void main(String[] args) {
		
		Data data = new Data();
		
		data.m = 10;
		data.n = 20;
		
		System.out.println("m =" + data.m + ",n =" + data.n);
		
		ValueTransferTest2 test = new ValueTransferTest2();
		test.swap(data);
		
		System.out.println("m =" + data.m + ",n =" + data.n);
		
	}
	
	public void swap(Data data) {
		int temp = data.m;
		data.m = data.n;
		data.n = temp;
	}
}


class Data{
	int m;
	int n;
}

        这段代码与上述代码的主要区别是swap()方法内的形参是一个引用数据类型,这是因为如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。我们可以结合如下的内存结构来一起理解。

         首先新new了一个对象data,在data栈空间存储的是对象的地址值,在堆空间存储的是相应对象中的属性,其默认值为0,接下来由data.m和data.n对堆空间中的m和n分别复制为10和20。接着对swap()方法实例化test,并将data这一引用数据类型传入形参中,由于此时赋给形参的是0x7788的地址值,形参中的data与main()方法中的data指向的是同一地址值,因此方法执行的步骤为:在栈中生成temp这一局部变量,然后将堆中m的值10赋给temp;将堆空间中n的值20赋给m,再将栈空间中temp的值10赋给堆空间中的n,实现m和n值的交换。完成后temp出栈,此时是真正的对m和n进行操作。

        再举个例子,对于数组元素的冒泡排序,因为很常用所以想把其封装成方法。那么错误的示例如下:

public class BubbleSortMethod {
	public static void main(String[] args) {
		int[] arr = new int[] {43,28,2,-21,28,99,58};
		BubbleSortMethod test = new BubbleSortMethod();
		test.sort(arr);
		test.print(arr);
	}
	//冒泡排序
	public void sort(int[] arr) {
		for(int i = 0;i < arr.length - 1;i++) {
			for(int j = 0;j < arr.length - 1 - i;j++) {
				if(arr[j] > arr[j + 1]) {
//					int temp = arr[j];
//					arr[j] = arr[j + 1];
//					arr[j + 1] = temp;
					
					swap(arr[j],arr[j + 1]);
				}
			}
		}
	}
	//数组打印
	public void print(int[] arr) {
		for(int i = 0;i < arr.length;i++) {
			System.out.print(arr[i] + "\t");
		}
	}
	
	public void swap(int i,int j) {
		int temp = i;
		i = j;
		j = temp;
	}
}

        与之前同理,此时对于swap()方法需要传入的也应给是引用数据类型,正确的方法如下:

public class BubbleSortMethod {
	public static void main(String[] args) {
		int[] arr = new int[] {43,28,2,-21,28,99,58};
		BubbleSortMethod test = new BubbleSortMethod();
		test.sort(arr);
		test.print(arr);
	}
	//冒泡排序
	public void sort(int[] arr) {
		for(int i = 0;i < arr.length - 1;i++) {
			for(int j = 0;j < arr.length - 1 - i;j++) {
				if(arr[j] > arr[j + 1]) {
//					int temp = arr[j];
//					arr[j] = arr[j + 1];
//					arr[j + 1] = temp;
					
					swap(arr,j,j + 1);
				}
			}
		}
	}
	//数组打印
	public void print(int[] arr) {
		for(int i = 0;i < arr.length;i++) {
			System.out.print(arr[i] + "\t");
		}
	}
		
	public void swap(int[] arr,int i,int j){
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;		
	}
}

补充说明:由于main()方法中由static关键字,所以在调用没有static的方法时必须通过实例化对象来调用,而sort()方法和swap()方法没有static关键字,所以可以直接调。

后记:写的有些墨迹,可能因为楼主比较笨,需要反复叨叨,欢迎补充和错误指正。

图片与知识来源:尚硅谷:Java教程——宋红康

  

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值