java函数中的值传递和引用传递问题

基本概念

值传递:传递对象的一个副本,即使副本被改变,也不会影响源对象,因为值传递的时候,实际上是将实参的值复制一份给形参。

引用传递:传递的并不是实际的对象,而是对象的引用,外部对引用对象的改变也会反映到源对象上,因为引用传递的时候,实际上是将实参的地址值复制一份给形参。

Java的函数传参方式都是值传递,唯一区别是形参是基本数据类型,还是引用数据类型,而这两种数据类型造成在函数体中修改了参数的额值,在函数体外是否跟着发生改变,根本原因是,两种数据类型变量在内存中存储的方式不一样,基本类型的变量保存原始值,即它代表的值就是数值本身;而引用类型的变量保存的是引用值,"引用值"指向内存空间的地址,代表了某个对象的引用,而不是对象本身,对象本身存放在这个引用值所表示的地址的位置。即基本类型的变量直接保存在函数调用栈中,而对象的变量的值其实是保存在堆中,然后将这个对象在堆中的值的地址引用存放到函数调用栈中。
————————————————
版权声明:本文为CSDN博主「凌凌小博客」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_35923749/article/details/79703700

基本数据类型(byte/short/int/long/float/double/char/boolean)

 public static void main(String[] args) {
        int a = 10,b=20;
        exchange(a,b);
        System.out.println("main: "+"a: "+a+" b: "+b);
		// a:10;b:20
    }
    static void exchange(int a,int b){
       int c = a;
       a = b;
       b= c;
        System.out.println("exchange: "+"a: "+a+" b: "+b);
        //a:20;b:10
    }

引用数据类型(String,类,数组)

String

   public static void main(String[] args) {
        String a = "123";
        exchange(a);
        System.out.println("main: "+"a: "+a);
        /**
        *	a = "456"; 
        *		a的值不会发生改变;a的引用会在栈内存中,引用的地址指向静态方法区的常量池中(先判断常量池中是否有‘456’,如果常量池中有‘456’直接引用)
        *	a = new String("456");
        *		a的值不会发生改变;a的引用会在栈内存中,引用指向的对象存在于堆内存当中(每new一次,便会产生一个新的‘456’对象)
        */
        

    }
    static void exchange(String a){
//       a = "456";  				a的值未改变 1
//       a = new String("456");    a的值未改变  2
		/**
		* 	在未赋值之前,exchange中的a和main中的a都的引用都指向堆内存中的同一对象‘123’,
		* 	赋值开始,系统会创建一个新的‘456’堆内存对象(假设堆里没有这个对象,2会创建一个新的,有的话1会直接引用)
		* 	然后让a的引用指向这个地址,此时exchange中的a和main中的a会变成两个截然不同的对象,分别指向不同的引用。
		*/
    }

字符串是一个特殊的数据类型,它的底层是一个final 型的ch[]数组,属于无法更改,所以字符串在作为参数传递时,可以当做一个特殊的数组进行操作,同样的它也是将复制一份原本的对象引用给了副本,此时副本对象的引用和原本对象的引用都指向原始字符串的位置,也就是exchange中的a和在刚开始初始化时它指向的地址和原对象main中的a指向的位置一致,即exchange中的a的初始hashcode值和原对象main中的a的hashcode值一样,exchange中的a经过a=“456”操作后,由于字符串的不可变性,此时会exchange中的a一个新的对象引用,即此时exchange中的a指向“456”的位置。exchange中的a的hashcode值会变化,但是原本main中的a它的对象引用没有发生改变,并且“123”也未发生改变,所以main中的a任然指向”123”。

StringBuffer

 public static void main(String[] args) {
//        String a = "123";
        StringBuffer a = new StringBuffer("123");
        exchange(a);
        System.out.println("main: "+"a: "+a);

    }
    static void exchange(StringBuffer a){
//       a = new StringBuffer("456");        //a的值未改变  1
//       a.append("456");                   //a的值发生改变 2
		
		/**
		*	1:原理同String一样,创建了新的对象
		*	2:append方法和insert方法都是对原字符串直接操作,所以会改变a的值
		*
		*/

    }

数组

public static void main(String[] args) {
        int a[] = {1,2,3};
        exchange(a);
        System.out.println(a[0]); //a[0]的值会发生改变,传递的是数组的引用
    }
    static void exchange(int a[]){
        a[0] = 100;
    }

对象

 public static void main(String[] args) {
        User a = new User(1, "tom");
        exchange(a);
        System.out.println(a.toString());
    }
    static void exchange(User a){
//        a = new User(1,"jack"); //值未变,a重新指向了堆内存当中的一个新对象
//        a.setName("jack"); // 值改变,直接对原来的对象进行操作,所以发生改变
    }

参考博客:

  1. https://blog.csdn.net/SummerOfFoam/article/details/109570841
  2. https://www.cnblogs.com/zwwhnly/p/10826530.html
  3. https://blog.csdn.net/weixin_43030796/article/details/81974190
  4. https://blog.csdn.net/weixin_48510456/article/details/107869715
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值