精华内容
下载资源
问答
  • java传递和引用传递
    千次阅读
    2021-02-26 08:26:02

    昨天博主在对于值传递和引用传递这里栽了一个大坑啊,导致一下午时间都浪费在这里,我们先说下值传递和引用传递java官方解释:

    值传递:(形式参数类型是基本数据类型):方法调用时,实际参数把它的值传递给对应的形式参数,形式参数只是用实际参数的值初始化自己的存储单元内容,是两个不同的存储单元,所以方法执行中形式参数值的改变不影响实际参数的值。

    引用传递:(形式参数类型是引用数据类型参数):也称为传地址。方法调用时,实际参数是对象(或数组),这时实际参数与形式参数指向同一个地址,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,这个结果在方法结束后被保留了下来,所以方法执行中形式参数的改变将会影响实际参数。

    通俗的来说值传递其实就是一传递一些具体数据,也就是基本类型的数据(1,2,"哈哈"....),引用传递是你传递的你自己分装的对象,或者是数据集合,list,array,set。。。

    我遇到的整好事对于list数据处理的问题,一言不合就上代码(测试代码):

    1.下面的代码是我从我自己写的一个demo,详细的表述了值传递和引用传递:

    1 @Test2 public voidck(){3 bean b = new bean("王","1");4 bean b2 = new bean("王","2");5 List list = new ArrayList();6 List list2 = new ArrayList();7 list.add(b);8 list.add(b2);9

    10 list2.addAll(list);11 list2.get(0).setName("哈哈哈");12

    13 for(bean bean : list2) {14 System.out.println(bean.getName()+"ssss"+bean.getAge());15 }16 for(bean bean1 : list) {17 System.out.println(bean1.getName()+"jjjjj"+bean1.getAge());18 }19

    20 }

    bean类

    1 public classbean {2

    3 privateString name ;4 privateString age;5

    6

    7

    8

    9

    10

    11 publicbean() {12 super();13 }14 publicbean(String name, String age) {15 super();16 this.name =name;17 this.age =age;18 }19 publicString getName() {20 returnname;21 }22 public voidsetName(String name) {23 this.name =name;24 }25 publicString getAge() {26 returnage;27 }28 public voidsetAge(String age) {29 this.age =age;30 }

    31 }

    按我们正常思路来说,list应该输出俩个

    list:

    王ssss1

    王ssss2

    list2:

    哈哈哈ssss1

    王ssss2

    但是:看我的运行结果

    1 哈哈哈ssss12 王ssss23 哈哈哈jjjjj14 王jjjjj2

    可以看到虽然只是修改了list2中的一个元素,但是list中的元素数据也被修改了,有同学可能就会说了list.addAll的问题,其实不是,重点就是bean这个,list2.addAll(list)

    这个方法其实是给list2赋值的bean的内存指针而不是把值拷贝到了list2的内存块中,也就是我们说的这里发生了引用传递而不是值传递,所以修改了list2中元素的值,也就修改

    了bean对象元素的值,list输出元素的值当然会改变,后来我是这样解决的:

    1 @Test2 public voidck(){3 bean b = new bean("王","1");4 bean b2 = new bean("王","2");5 List list = new ArrayList();6 List list2 = new ArrayList();7 list.add(b);8 list.add(b2);9

    10 for(int i=0;i

    18 for(bean bean : list2) {19 System.out.println(bean.getName()+"ssss"+bean.getAge());20 }21 for(bean bean1 : list) {22 System.out.println(bean1.getName()+"jjjjj"+bean1.getAge());23 }24

    25 }26

    在在list赋值给list2的时候,我把bean对象新new了一个并且遍历list中的bean属性值给新new的这个bean对象,这样传递的是基本类型数据也就是copy到新new的bena内存块中,这样list2在怎么修改也不会影响到list中的值,因为他们包涵的bean对象是两不同指针的对象,这是修改后的输出结果:

    1 list2:2 哈哈哈ssss13 王ssss24 list:5 王jjjjj16 王jjjjj2

    我的个人理解哈,大家有什么其他更加简便的方法和理解留言哈,互相学习

    更多相关内容
  • java 没有引用传递,都是传递的,可以通过传递副本修改对象的,副本交换,并不影响原引用
  • 主要介绍了详解java传递、地址传递、引用传递的相关资料,需要的朋友可以参考下
  • 当一个变量为一个参数传入方法内部的时候,会有两种不同的传递方式:传递和引用传递。  传递的特点:不管方法内部对传进去的参数作任何改变,也不会影响方法外部的变量的  引用传递的特点:方法内部对传...
  • 主要介绍了 Java 传递和引用传递详解及实例代码的相关资料,需要的朋友可以参考下
  • 主要介绍了java通过实例了解传递和引用传递,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 主要介绍了探讨Java中函数是传递还是引用传递问题,非常不错,具有参考借鉴价值,需要的朋友可以参考下
  • 为什么 Java 只有传递,但 C++ 既有传递,又有引用传递呢?今天我们就来探讨下这个问题,有需要的朋友可以参考下
  • Java中传递和引用传递

    千次阅读 2022-01-15 12:22:33
    传递 / 引用传递 传递:就是在方法调用的时候,实参是将自己的一份拷贝赋给形参,在方法内,对该参数的修改不影响原来的实参。 引用传递:是在方法调用的时候,实参将自己的地址传递给形参,此时方法内对该...

    值传递 / 引用传递
    值传递:就是在方法调用的时候,实参是将自己的一份拷贝赋给形参,在方法内,对该参数值的修改不影响原来的实参。

    引用传递:是在方法调用的时候,实参将自己的地址传递给形参,此时方法内对该参数值的改变,就是对该实参的实际操作。

    Java中只有值传递
    首先回顾一下在程序设计语言中有关将参数传递给方法(或函数)的一些专业术语。

    按值调用(call by value):表示方法接收的是调用者提供的值。

    按引用调用(call by reference):表示方法接收的是调用者提供的变量地址。

    它用来描述各种程序设计语言(不只是 Java)中方法参数传递方式。

    Java 程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个拷贝,即,方法不能修改传递给它的任何参数变量的内容。

    swap( ) 场景
    要求写一个函数交换int类型的a和b的值

    在 swap() 方法中,a、b 的值进行交换,并不会影响到 A、B。因为,a、b 中的值,只是从 A、B 复制过来的。也就是说,a、b 相当于 A、B 的副本,副本的内容无论怎么修改,都不会影响到原件本身。

    如果我们这么写:

    public class test{
      
        public static void main(String[] args) {
              int A = 2;
              int B = 3;
              swap(A, B);
            System.out.println(A);
            System.out.println(B);
        }
        
          public static void swap(int a, int b){
            int tmp = a;
            a = b;
            b = tmp;
            }
    }


    运行结果为:

    2
    3


    发现A和B的值并没有交换,为什么呢?

    因为Java中采用的是值传递,也就是说执行swap(int a, int b)时,这里的参数a和b,只是A和B的副本,函数的运行结果并没有改变原来A和B的值。

    那么采用Integer呢?

    如果将上面的int类型转变为Integer,swap(Integer a, Integer b)会不会实现交换功能呢?

    public class test{
      
        public static void main(String[] args) {
              Integer A = 2;
              Integer B = 3;
              swap(A, B);
            System.out.println(A);
            System.out.println(B);
        }
        
          public static void swap(Integer a, Integer b){
            Integer tmp = a;
            a = b;
            b = tmp;
            }
    }


    运行结果为:

    2
    3


    可见还是没有完成交换!

    去查看Integer的源码:

    public final class Integer extends Number implements Comparable<Integer> {}

    可以看到Integer使用final修饰的int进行存储。final修饰的变量不能被重新赋值,所以操作参数传递变量时,实际上是操作变量对象的副本(Java中的包装类型都是默认使用这种方式实现的,使用拷贝副本的方式提升效率和减少内存消耗)。

    如果换作是数组呢?

    public static void main(String[] args) {
        int[] arr = { 1, 2, 3, 4, 5 };
        System.out.println(arr[0]);
        change(arr);
        System.out.println(arr[0]);
    }

    public static void change(int[] array) {
        // 将数组的第一个元素变为0
        array[0] = 0;
    }


    运行结果为:

    1

    0


    这里方法array是对象的引用arr的拷贝,而不是对象本身的拷贝,因此, array 和 arr 指向的是同一个数组对象。

    如果换做是一般对象呢?

    很多程序设计语言(特别是 C++ 和 Pascal)提供了两种参数传递的方式:值调用和引用调用。

    有些程序员(甚至本书的作者)认为 Java 程序设计语言对对象采用的是引用调用,实际上,这种理解是不对的。由于这种误解具有一定的普遍性,所以下面给出一个反例来详细地阐述一下这个问题。

    class User {
        private String name;

        public User(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return name;
        }
    }


    测试:

    public class test{
            public static void main(String[] args) {
            User A = new User("ali");
            User B = new User("bd");
            System.out.println("交换前name:" + A + "-->" + B);
            swap(a,b);
            System.out.println("交换后name:" + A + "-->" + B);
        }

        private static void swap(User a, User b) {
            User tmp = a;
            a = b;
            b = tmp;
        }
    }


    运行结果为:

    交换前name:ali-->bd
    交换后name:ali-->bd


    发现还是没有交换!

    所以到底有没有交换,主要是看它修改的是变量(引用)还是修改的堆里面的对象。

    交换前:


    交换后:

     

     


    通过上面两张图可以很清晰的看出: 方法并没有改变存储在变量 A 和 B 中的对象引用。swap() 方法的参数 a 和 b 被初始化为两个对象引用的拷贝,这个方法交换的是这两个拷贝。

    那么到底该如何实现交换两个变量的值呢?

    用容器(或者数组)
    例如:

    public class test{

        public static void main(String[] args) {
            int[] arr = {2, 3};
            int A = arr[0];
            int B = arr[1];
            swap(arr, 0, 1);
            A = arr[0];
            B = arr[1];
            System.out.println(A);
            System.out.println(B);
        }

        public static void swap(int[] arr, int a, int b){
            int tmp = arr[a];
            arr[a] = arr[b];
            arr[b] = tmp;
        }
    }


    运行结果为:

    3
    2


    用反射


    public static void swap(Integer a, Integer b) throws Exception {
        Field field = Integer.class.getDeclaredField("value");
        field.setAccessible(true);   //设置可以访问成员的私有不可变的变量
        Integer tmp =new Integer(a.intValue());
        field.set(a, b.intValue());
        field.set(b, tmp);
    }

    展开全文
  • 主要介绍了JAVA参数传递方式,结合实例形式分析了java传递与引用传递区别及相关操作注意事项,需要的朋友可以参考下
  • 参数是按而不是按引用传递的说明 Java 应用程序有且仅有的一种参数传递机制,即按传递。写它是为了揭穿普遍存在的一种神话,即认为 Java 应用程序按引用传递参数,以避免因依赖“按引用传递”这一行为而导致的...
  • Java:按传递还是按引用传递详细解说
  • 主要介绍了java到底是传递还是引用传递的相关知识,本文通过几个例子给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
  • 主要为大家详细介绍了Java值传递和引用传递,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • Java传递还是引用传递

    万次阅读 多人点赞 2019-03-20 02:40:16
    最近整理面试题,整理到传递、引用传递,到网上搜了一圈,争议很大。带着一脸蒙圈,线上线下查了好多资料。最终有所收获,所以分享给大家,希望能对你有所帮助。 首先说下我的感受,这个题目出的很好,但是在 ...

        最近整理面试题,整理到值传递、引用传递,到网上搜了一圈,争议很大。带着一脸蒙圈,线上线下查了好多资料。最终有所收获,所以分享给大家,希望能对你有所帮助。
        首先说下我的感受,这个题目出的很好,但是在 Java 中这个题目是有问题的(在下面我会解释)。并且,有很多结论是 Java 中只有 值传递。我认为这样说不够严谨。当然如果针对 Java 语言本身来讲,Java 中只有 值传递,没有引用传递,是正确的。但是如果针对 值传递,引用传递定义来说,Java 中还是有引用传递的。下面来分析:

    一、值传递、引用传递定义


        在深入分析问题之前,先让初问者简单明白一下什么是值传递,引用传递。我先用 Java 代码解释:

    public class StringBase {
    
        public static void main(String[] args) {
            int c = 66; //c 叫做实参
            String d = "hello"; //d 叫做实参
    
            StringBase stringBase = new StringBase();
            stringBase.test5(c, d); // 此处 c 与 d 叫做实参
    
            System.out.println("c的值是:" + c + " --- d的值是:" + d);
        }
        
        public void test5(int a, String b) { // a 与 b 叫做形参
            a = 55;
            b = "no";
        }
    }


    【运行结果】
    c的值是:66 --- d的值是:hello

    可以看出通过方法传递后,int 类型与 String 类型的原值并没有受到前面 test5 方法执行后的影响,还是输出了原值。这种形为通常被说成值传递。如果原值经过 test5 方法后被改变了,这种形为通常被描述为引用传递

    定义

        值传递:指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
        引用传递:是指在调用函数时将实际参数的地址直接传递到函数中(的形参),那么在函数中对参数所进行的修改,将影响到实际参数。
        引用传递:形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作。(下面文章中 C++ 的定义,我觉得这样说更精简形象一些,所以放了两个定义,其实意思是一样的)

        以上,就是相关的定义,大家对这个定义几乎没有分歧,但是我建议大家,有必要去看看 C++ 中 值传递、引用传递的定义。因为在 C++ 中有三个定义:值传递、引用传递、指针传递,推荐一个地址: C++ 值传递、指针传递、引用传递详解

    //引用传递
    void change2(int &n) {
        cout << "引用传递--函数操作地址" << &n << endl;
        n++;
    }

        我们看上边 C++ 引用传递的代码,使用的 & 操作符。& 操作符在 C++ 中被定义为"引用",引用在 C++ 中的定义是“引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样”,再看引用其中的一个描述:“声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元”。因此这引用的概念在 Java 中根本不存在。Java 中哪有给变量起个别名的!!!
        因此说,这个题出的就有问题,在 Java 官方中我一直没有找到明确的证据说“Java 中 值传递、引用传递 的定义”我所看到的全是说 C++ 中关于值传递、引用传递的定义。但是,在 Java 中没有 C++ 里"引用"的概念。Java 里只有对象,new 关键字。这就很尴尬了,拿 C++ 中的定义,来解释 Java,我觉得这就是有问题的。问题就出在了引用传递!!!
        在 C++ 中关于引用传递的定义明确,代码解释清晰。在 C++ 中引用传递,传递的是一个别名,操作别名就跟操作原值一个样。
        然而在 Java 中,没有引用的概念,Java 中只要定义变量就会开辟一个存储单元。因此,对 Java 语言来说只有值传递,没有引用传递是正确的。
        虽然 Java 中没有引用(C++ 中 引用"&")。但是,引用传递的定义,在 Java 中还是有符合条件的。抛开语言中的特性。只针对:值传递、引用传递的定义我们来分析一下,Java 是属于值传递还是引用传递。
        要想知道 Java 是属于值传递还是引用传递,这就要从 Java 内存模型聊起了,我们来看基本数据类型与引用类型在内存中的存储方式。

    二、基本数据类型、引用类型

    1.基本数据类型、引用类型定义
        基本数据类:Java 中有八种基本数据类型“byte、short、int、long、float、double、char、boolean”
        引用类型:new 创建的实体类、对象、及数组
    2.基本数据类型、引用类型在内存中的存储方式
        基本数据类型:存放在栈内存中。用完就消失。
        引用类型:在栈内存中存放引用堆内存的地址,在堆内存中存储类、对象、数组等。当没用引用指向堆内存中的类、对象、数组时,由 GC回收机制不定期自动清理。
    3.基本类型、引用类型内存简单说明图


        好,看了基本的内存图,应该能明白 Java 是属于值传递还是引用传递。不明白,也没关系,下面会详细说明,先说引起争议的代码。

    三、在 Java 中 值传递 与 引用传递,产生模糊不清的代码

    public class TransmitTest {
    
        public static void main(String[] args) {
    
            String a = "hello"; //String 引用数据类型,调用 pass 方法后 b 的值没有改变,不是 hello
            int b = 1; //int 基本数据类型,调用 pass 方法后 a 的值没有改变,还是 1
    
            User user = new User(); //new Class 引用类型,调用 pass 方法后 name 与 age 的值改变了
            user.setName("main"); // 调用 pass 后,name 为 pass 了
            user.setAge(2); //调用 pass 后,age 为 4 了
    
            pass(user, a, b); //pass 方法调用
    
            System.out.println("main 方法 user 是:" + user.toString());
            System.out.println("main 方法 a 的值是:" + a + " --- b 的值是:" + b);
        }
    
        public static void pass(User user, String a, int b) {
    
            a = "你好";
            b = 3;
    
            user.setName("pass");
            user.setAge(4);
    
            System.out.println("pass 方法 user 是:" + user.toString());
            System.out.println("pass 方法 a 的值是:" + a + " --- b 的值是:" + b);
        }
    }
    
    class User {
    
        String name;
        int age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "name = " + name + " --- age = " + age;
        }
    }

    【运行结果】
    pass 方法 user 是:name = pass --- age = 4
    pass 方法 a 的值是:你好 --- b 的值是:3
    main 方法 user 是:name = pass --- age = 4
     

        main 方法 a 的值是:hello --- b 的值是:1    结果分析,int b,实参是 1,pass 方法调用后,值还是 1 没变,说明基本数据类型是值传递,大家对这个也几乎没争议。
    争议的在下边了:
            1.String a 是引用类型,pass 方法调用后,值还是 hello 没变。(结论:好像引用类型也是值传递啊!!!)
            2.new User() 也是引用类型,在方法调用后,值居然变了。原值不应该是 name = main,age = 2 的吗?为什么 name = pass,age = 4 了呢?(结论:引用类型好像是引用传递啊???)
        这就奇葩了,String 与 new 创建的类,同为引用类型,为什么产生的结果不一样呢?String 不也是一个类吗?User 不也是一个类吗?
        有人解释说这个代码比喻的不对,应该用如下代码比喻,在 pass 方法中添加一行代码,user = new User(),pass 方法修改如下:

    public static void pass(User user, String a, int b) {
    
        a = "你好";
        b = 3;
    
        user = new User();
        user.setName("pass");
        user.setAge(4);
    
        System.out.println("pass 方法 user 是:" + user.toString());
        System.out.println("pass 方法 a 的值是:" + a + " --- b 的值是:" + b);
    }


    【运行结果】
    pass 方法 user 是:name = pass --- age = 4
    pass 方法 a 的值是:你好 --- b 的值是:3
    main 方法 user 是:name = main --- age = 2
    main 方法 a 的值是:hello --- b 的值是:1

        这样一来,改变了形参的值,但是实参没有改变。因此有人得出结论,Java 中只有值传递,没有引用传递。(我并不这么认为,原因如下)
        使用 user = new User() 这个代码来做验证,我觉得是符合 String 类型做形参时的验证地,但是,此示例不符合引用传递的验证
        在验证之前,我们先看下使用 user=new User(); 语句之前与之后的内存模型图,能有助于我们更好的验证结果,同时也有助于更好的理解 Java 内存模型。我们看 TransmitTest 类在 Java 内存模型中的存储图:

    图1 pass() 方法中没有使用 user=new User() 语句的内存模型图


        在 图1 中,main() 方法中的 user 类,与 pass() 方法中的 user 类,指向的是同一个堆内存中的 User 类,红色虚线是在 main() 方法中初次给 name 属性赋的值"main"。实线部分,是在 pass() 方法中给 name 属性赋的值"pass"。因为在堆内存中只有一个 User 类实体,因此 main() 方法与 pass() 方法中的 user 指向的都是同一个 User 类 0x000031。因此,无论在 main() 方法还是 pass() 方法中,改变其 user 的属性值后,打印 User 类的属性值肯定是一样的,他们用的是一个实体类。

    图2 pass() 方法中使用了 user=new User() 语句的内存模型图


        在 图2 中,main() 方法中的 user 类首次加载,堆内存开辟了一个地址为 0x000031 的 User 类实体。当把 main() 方法中的实参 user 传递给 pass() 方法中形参 user 的时候,栈内存在 pass() 方法区中开辟了一个空间,并引用了地址为 0x000031 的 User 类。此时两个方法中的 User 类其实是一个。
        然而当 pass() 方法中的 user=new User()语句执行后,堆内存中新开辟了一个地址为 0x000032 的 User 类,pass() 方法中的 user 从此指向了地址为 0x000032 的 User 类。
        因为 pass() 方法 与 main() 方法中的 user 属性分别指向了不同的 User 类,所以两个方法中的 User 类的属性无论怎么修改,相互都不影响。
        但是,这种操作是不能验证引用传递定义的。因为实参传值给形参后,形参自己改变了地址,这就和引用传递无关了。我们再来用代码验证。
        我们可以使用 C++ 引用传递代码来验证,使用 user = new User() 语句验证引用传递的错误性
    C++ 中引用传递代码

    class User
    {
    public:
        int age;   // 长度
        string name;  // 宽度
    };
    
    
    //引用传递
    void pass(User &user) {
    
        cout << "引用传递 -- user的地址是:" << &user << endl;
    
        user.age = 2;
        user.name = "你好";
    }
    
    
    int main() {
    
        User user;
        user.age = 1;
        user.name = "hello";
    
        cout << "实参 -- user的地址是:" << &user << endl;
        pass(user);
        cout << "实参 -- user的值 age=" << user.age << ",name=" << user.name << endl;
    
        system("pause");
        return false;
    }


    【运行结果】
    实参 -- user的地址是:00DCF768
    引用传递 -- user的地址是:00DCF768
    实参 -- user的值 age=2,name=你好

        在 C++ 中,引用传递的实参与形参地址一致,在引用的方法中,使用的就是实参的地址。当修改形参值后,实参值也跟着变。现在我们按照 user=new User(); 的方法改变一下引用方法 pass 如下:

    //引用传递
    void pass(User &user) {
    
        cout << "引用传递 -- user的地址是:" << &user << endl;
    
        User user2 = user; //相当于 Java 中的 user=new User();
        cout << "引用传递 -- user2的地址是:" << &user2 << endl;
    
        user2.age = 2;
        user2.name = "你好";
    }


    【运行结果】
    实参 -- user的地址是:00CFFACC
    引用传递 -- user的地址是:00CFFACC
    引用传递 -- user2的地址是:00CFF9AC
    实参 -- user的值 age=1,name=hello

        我们看,改变引用传递中形参 user 的地址后(后期改变的地址,这跟引用传递,值传递还有什么关系?),再修改形参 user 的值,实参没有任何变化。这就破坏了引用传递的场景,因此不能使用 user=new User(); 语句来验证引用传递的定义。

        排除了其他异议,我们再来分析 Java 中有没有引用传递。

    先把引用传递的定义放上

        引用传递:是指在调用函数时将实际参数的地址直接传递到函数中(的形参),那么在函数中对参数所进行的修改,将影响到实际参数。
        引用传递:形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作。

        经过上面的长篇大论,我想这时候你应该能明白了。在对引用类型做方法传递的时候,是不是先把实参的地址给形参的?之后对形参的操作是,是不是相当于操作实参?最后有没有影响到实际参数?
    答案肯定都是有的。

    定义关键1:是指在调用函数时将实际参数的地址直接传递到函数中(给形参了)
        证明:Java 在进行方法调用传递引用类型参数的时候,就是先给形参一个与实参相同的地址的(此处与 C++ 的不同之处是,C++ 是别名,没有在内存中给形参开辟空间,而 Java 给形参开辟了一个栈内存空间,存放与实参相同的引用地址。但是这与引用传递的定义不违背啊!!!定义可没说形参是否有开辟空间的概念)。

    定义关键2:在函数中对参数所进行的修改,将影响到实际参数。
        证明:Java 在进行方法调用传递引用类型参数后,修改形参的内容后,就是影响了实参的值。

    四、String 与包装类的特殊分析

        好了,解决了实例对象,我们再来说 String 与包装类,为什么 String 与包装类作为引用类型,却有值传递的功能,居然没有影响到实参!

    原因如下
        我们都知道。String 类型及其他七个包装类,是一群特殊群体。当使用 String a = "hello"; 语句时,相当于执行了 String a = new String("hello")。然而在 Java 中每一次 new 都是一次对象的创建。如果你创建的对象在堆中不存在,便会创建一个,如果是新创建的对象,那么地址都会变的,后期改变的地址,这跟引用传递,值传递还有什么关系?

        其实 String 型方法参数传值的过程,可以用以下代码来解释,我们先看 String 类型的还原:

    String a = "hello"; //a 相当于实参
    String a1 = a; //a1 就相当于形参
    a1 = "你好";
    System.out.println("a是:" + a + " --- a1是:" + a1);


    【运行结果】
    a是:hello --- a1是:你好

    逐步还原解释:
        String a = "hello"; 在 String 池中检查并创建一个常量:"hello",给 a 分配一个栈内存,在此存储常量 hello 的地址。
        String a1 = a; 给 a1 分配一个栈内存,在此存储常量 hello 的地址。相当于 a 把自己持有的地址,复制给了 a1。

    内存图如下


        a1 = "你好"; 等同于 a1 = new String("你好")。在 String 池中检查是否有 "你好" 的常量。如果有,将 a1 的地址指向 "你好" 的地址。如果 String 池中没有 "你好" 常量,在堆内存中创建 "你好" 常量,并将 a1 地址指向 "你好"。

    内存图如下


        总结如下:String 类型,在进行方法传参的时候,是先将实参地址,赋值给形参(形参在栈内存中确实新开辟了一个新的内存空间,用于存储地址)。但是当再次给 String 类型的形参赋值(与实参内容不一样的值时),形参地址变了,这就和引用传递无关了。我们可以用 C++ 代码中的引用传递,来验证 String 型的这一特殊情况,代码如下:

    //引用传递
    void pass(string &a, int &b) {
    
        cout << "引用传递 -- a的地址是:" << &a << " --- b的地址是:" << &b << endl;
        cout << "引用传递 -- a的值是:" << a << " --- b的值是:" << b << endl;
    
        string c = a; // 相当于 java 中的 new String
        int e = b;
    
        cout << "引用传递 -- c的地址是:" << &c << " --- e的地址是:" << &e << endl;
        cout << "引用传递 -- c的值是:" << c << " --- e的值是:" << e << endl;
    
        c = "你好"; //在引用传递中改变形参地址后做修改操作,不影响实参
        e = 2; //在引用传递中改变形参地址后做修改操作,不影响实参
    }
    
    int main() {
        string a = "hello";
        int b = 1;
    
        cout << "实参 -- a的地址是:" << &a << " --- b的地址是:" << &b << endl;
    
        pass(a, b);
    
        cout << "实参 -- a的值是:" << a << " --- b的值是:" << b << endl;
    
        system("pause");
        return false;
    }


    【运行结果】
    实参 -- a的地址是:00CFF9CC --- b的地址是:00CFF9C0
    引用传递 -- a的地址是:00CFF9CC --- b的地址是:00CFF9C0
    引用传递 -- a的值是:hello --- b的值是:1
    引用传递 -- c的地址是:00CFF8A0 --- e的地址是:00CFF894
    引用传递 -- c的值是:hello --- e的值是:1
    实参 -- a的值是:hello --- b的值是:1

        我们看,在 C++ 中的引用传递方法中,改变形参的地址后做修改操作,照样不影响实参的值,这就破坏了引用传递的本质,不能这样比喻。

        因此,String 与其他包装类,在做形参的时候,由于他们在赋不同于实参的值时,改变了形参的地址,因此使引用传递,看起来像值传递,其实本质还是引用传递。


    五、总结


    1.这个题目出的不严谨,但是很好(因为涉及了 Java 内存模型)
    2.就 Java 语言本身来说,只有值传递,没有引用传递。
    3.根据 值传递,引用传递的定义来说:
            Java 中的基本类型,属于值传递。
            Java 中的引用类型,属于引用传递。
            Java 中的 String 及包装类,属于特殊群体,作为形参时,由于每次赋值都相当于重新创建了对象,因此看起来像值传递,但是其特性已经破坏了,值传递、引用传递的定义。因此他们属于引用传递的定义,却表现为值传递。

    此题争议很大,我仅分享自己的理解,如有不同结论,欢迎指正,一起共勉!

    展开全文
  • 本文介绍了“java中传递和引用传递的区别分析”,需要的朋友可以参考一下
  • 主要介绍了Java中值传递和引用传递的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • public class Test3 {public static void change(int a){a=50;}public static void main(String[] args) {int a=10;System.out.println(a);change(a);System.out.println(a);...main方法中将a传递给change方法,chan...

    public class Test3 {

    public static void change(int a){

    a=50;

    }

    public static void main(String[] args) {

    int a=10;

    System.out.println(a);

    change(a);

    System.out.println(a);

    }

    }

    输出的 是10,10。main方法中将a传递给change方法,change方法中会对传递过来的参数进行copy,所以change中的a是实参复制出来的一个变量。change中的a的改变与实参无关。

    public class Test3 {

    public static void change(int []a){

    a[0]=50;

    }

    public static void main(String[] args) {

    int []a={10,20};

    System.out.println(a[0]);

    change(a);

    System.out.println(a[0]);

    }

    }

    输出结果为10   50。实际传递的是引用的地址值。形参获取到实参所指向的地址的指针。改变形参的值相当于改变实参指向地址的值,所以实参指向的值会改变。

    class Emp {

    public int age;

    }

    public class Test {

    public static void change(Emp emp)

    {

    emp.age = 50;

    emp = new Emp();//再创建一个对象

    emp.age=100;

    }

    public static void main(String[] args) {

    Emp emp = new Emp();

    emp.age = 100;

    System.out.println(emp.age);

    change(emp);

    System.out.println(emp.age);

    System.out.println(emp.age);

    }

    }

    48304ba5e6f9fe08f3fa1abda7d326ab.png

    输出为:100  50  50.

    首先,方法中改变了对象的值,所以age为50,然后创建了一个新的对象,新的对象的指针放在了emp里。这时的emp和传递过来的emp所指向的地址不同了。最后设置age为100,是对新建的Emp对象的设置。也就是说,后来新建的emp相当于change方法中的私有变量,作用域只在change方法里。而传递过来的emp的指针是不会改变的。所以打印的emp是实参指向的空间。

    展开全文
  • 本文通过实例代码给大家介绍了Java中的按传递引用传递的相关知识,感兴趣的朋友跟随脚本之家小编一起学习吧
  • 为什么Java只有值传递

    2021-01-20 02:08:46
    我们先看一下传递引用传递的概念...传递的函数中无法改变原始对象,引用传递中函数 可以改变原始对象 我们通过例子理解一下Java传递: public static void main(String[] args) { int a = 10; int b = 20;
  • 有说有传递和引用传递两种,也有说只有传递的,这里只说下个人见解  先看一个例子 public class Test1 { public static void main(String[] args) { int a = 10; changeNum(a); System.out.println("main...
  • 主要介绍了解析Java传递还是按引用传递,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 快速区分传递和引用传递
  • java中传递和引用传递的区别?

    千次阅读 多人点赞 2018-11-29 21:04:51
    1.值传递概念:值传递是指在调用函数时将实际参数复制一份传递到函数,这样在函数如果对参数进行修改,将不会影响到实际参数。 实例: public class Main { public static void main(String[] args) { int ...
  • Java中传递和引用传递的区别.doc
  • Java值传递与引用传递的区别

    千次阅读 多人点赞 2021-09-09 22:55:57
    文章目录Java值传递与引用传递前景实参与形参传递与引用传递Java中传递总结 前景 关于这个问题,引发过很多广泛的讨论,看来很多程序员对于这个问题的理解都不尽相同,甚至很多人理解的是错误的。还有的人可能...
  • java中的参数传递(只有传递没有引用传递

    万次阅读 多人点赞 2019-07-31 19:25:14
    Java中只有传值调用(传递),没有传址调用(址传递或者引用传递)。所以在java方法改变参数的是不会改变原变量的的,但为什么改变引用变量的属性却可以呢?请看下面的解答。 java中的数据类型 Java中...
  • Java中的参数传递,到底是传递还是引用传递? 错误理解一:传递和引用传递,区分的条件是传递的内容,如果是个,就是传递。如果是个引用,就是引用传递。 错误理解二:Java引用传递。 错误理解三:传递的...
  • java中传递和引用传递[汇编].pdf

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 400,057
精华内容 160,022
关键字:

java中的值传递和引用传递

java 订阅