精华内容
下载资源
问答
  • 为什么Java只有值传递

    2021-01-20 02:08:46
    我们先看一下值传递和引用传递的概念和区别 值传递:是指在调用函数时将实际参数复制一份传递到函数中,...我们通过例子理解一下Java值传递: public static void main(String[] args) { int a = 10; int b = 20;
  • 为什么Java只有值传递?? 值传递: 调用函数时,将实参复制一份传给函数,函数中修改参数时不会影响实参 引用传递:调用函数时,将实参的地址传给函数,函数中修改参数会影响实参。 判断是值传递还是引用传递的标准...

    为什么Java只有值传递??

    值传递: 调用函数时,将实参复制一份传给函数,函数中修改参数时不会影响实参

    引用传递:调用函数时,将实参的地址传给函数,函数中修改参数会影响实参。

    判断是值传递还是引用传递的标准,和传递参数的类型是没有关系的。

    Java中的栈与堆

    • 栈:存放基本类型的局部变量,与对象的引用,方法执行结束后栈中的变量和对象的引用消失。

    • 堆:存放对象的实例。java中的数组和new出来的对象都是放在堆中的,堆中的对象没有任何引用(就是在栈中没有任何一个变量指向该对象)时会被GC回收。

    1-值传递

    public class TestNum {
        public static void main(String[] args) {
            int num = 3;
            System.out.println("修改前的num值:"+num);
            changeValue(num);
            System.out.println("修改后的num值:"+num);
        }
    
        private static void changeValue(int num) {
            num = 5;
            System.out.println("形参num值:"+num);
        }
    }
    

    结果:

    修改前的num值:3
    形参num值:5
    修改后的num值:3
    

    值传递不是简单的把实参传递给形参,而是,实参建立了一个副本,然后把副本传递给了形参。图中num是实参,然后创建了一个副本temp,把它传递给形参value,修改value值对实参num没有任何影响。

    image

    2-引用传递

    package java_learn;
    
    class User {
        private int age;
        private String name;
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public User(int age, String name) {
            this.age = age;
            this.name = name;
        }
    
        public User() {
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "age=" + age +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
    public class TestUser {
        public static void main(String[] args) {
            User user = new User(18, "zhangsan");
            System.out.println("修改对象前:"+user);
            changeUser(user);
            System.out.println("修改对象后:"+user);
        }
    
        private static void changeUser(User user) {
            user.setAge(20);
            user.setName("lisi");
        }
    }
    
    

    结果:

    修改对象前:User{age=18, name='zhangsan'}
    修改对象后:User{age=20, name='lisi'}
    

    可以发现,传过去的user对象,属性值被改变了。由于,user对象存放在堆里边,其引用存放在栈里边,其参数传递图如下。

    user是对象的引用,为实参,然后创建一个副本temp,把它传递给形参user1。但是,他们实际操作的都是堆内存中的同一个User对象。因此,对象内容的修改也会体现到实参user上。
    image

    3-传递类型是String类型

    public class TestStr {
        public static void main(String[] args) {
            String str = new String("zhangsan");
            System.out.println("字符串修改前:"+str);
            changeStr(str);
            System.out.println("字符串修改后:"+str);
        }
    
        private static void changeStr(String str) {
            str = "lisi";
        }
    }
    

    结果:

    字符串修改前:zhangsan
    字符串修改后:zhangsan
    

    String也是引用类型,为什么在这又不变了呢?传递参数是引用类型,并不代表就是引用传递,其实它还是值传递。

    图中,str是对象 zhangsan的引用,为实参,然后创建了一个副本temp,把它传递给了形参str1。此时,创建了一个新的对象 lisi ,形参str1指向这个对象,但是原来的实参str还是指向zhangsan。因此,形参内容的修改并不会影响到实参内容。

    所以,两次打印结果都是zhangsan。
    image

    总结:

    值传递,不论传递的参数类型是值类型还是引用类型,都会在调用栈上创建一个形参的副本。不同的是,对于值类型来说,复制的就是整个原始值的复制。而对于引用类型来说,由于在调用栈中只存储对象的引用,因此复制的只是这个引用,而不是原始对象。

    最后,再次强调一下,传递参数是引用类型,或者说是对象时,并不代表它就是引用传递。引用传递不是用来形容参数的类型的,不要被“引用”这个词本身迷惑了。这就如同我们生活中说的地瓜不是瓜,而是红薯一样。

    • 参数传递时,是拷贝实参的副本,然后传递给形参。(值传递)
    • 在函数中,只有修改了实参所指向的对象内容,才会影响到实参。
    展开全文
  • 什么值传递? 方法调用时,实际参数把它的值传递给对应的形式参数,方法执行中形式参数的改变不影响实际参数的值 值实参形参 什么是引用传递? 也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被...

    什么是值传递?

    方法调用时,实际参数把它的值传递给对应的形式参数,方法执行中形式参数的改变不影响实际参数的值

    实参
    形参

    什么是引用传递?

    也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,方法执行中形式参数值的改变将会影响实际参数的值。

    值传递和引用传递(不是引用类型传递)的区别?

    值传递 引用传递
    根本区别 会创建副本(Copy) 不创建副本
    所以 函数中无法改变原始对象 函数中可以改变原始对象

    而在JAVA中只有值传递,基本类型传递的是值的副本,引用类型传递(不是上面说的引用传递)的是引用的副本。

    值传递example:

    public static void main(String[] args) {
          int num1 = 3;
          int num2 = 4;
          change(num1, num2);
          System.out.println(num1); // 打印 3
          System.out.println(num2); // 打印 4
      }
    
      public static void change(int a, int b) {
          int temp = a;
          a = b;
          b = temp;
      }
    

    在这里插入图片描述
    分析:在swap方法中,a、b的值进行交换,并不会影响到 num1、num2。因为,a、b中的值,只是从 num1、num2 的复制过来的。也就是说,a、b相当于num1、num2 的副本,副本的内容无论怎么修改,都不会影响到原件本身。

    引用传递example:

     public static void main(String[] args) {
          int[] arr = {1, 2, 3, 4, 5};
          System.out.println(arr[0]); //打印 1
          change(arr);
          System.out.println(arr[0]); // 打印 0
      }
    
      public static void change(int[] array) {
          // 将数组的第一个元素变为0
          array[0] = 0;
      }
    

    在这里插入图片描述
    分析:array 拷贝的是arr对象的引用,也就是说 array 和 arr 指向的时同一个数组对象。 因此,外部对引用对象的改变会反映到所对应的对象上。


    很多程序设计语言(特别是,C++和Pascal)提供了两种参数传递的方式:值调用和引用调用。有些程序员(甚至本书的作者)认为Java程序设计语言对对象采用的是引用调用,实际上,这种理解是不对的。由于这种误解具有一定的普遍性,所以下面给出一个反例来详细地阐述一下这个问题。


    反例example

    public class Test {
    	public static void main(String[] args) {
    		Student s1 = new Student("小张");
    		Student s2 = new Student("小李");
    		Test.swap(s1, s2);
    		System.out.println("s1:" + s1.getName()); // 小李
    		System.out.println("s2:" + s2.getName()); // 小张
    	}
    
    	public static void swap(Student x, Student y) {
    		// x,y交换
    		Student temp = x;
    		x = y;
    		y = temp;
    		
    		System.out.println("x:" + x.getName()); // 小张
    		System.out.println("y:" + y.getName()); // 小李
    	}
    }
    

    分析:方法并没有改变存储在变量 s1 和 s2 中的对象引用。swap方法的参数x和y被初始化为两个对象引用的拷贝,这个方法交换的是这两个拷贝

    总结:

    • 一个方法不能修改一个基本数据类型的参数(即数值型或布尔型)
    • 一个方法可以改变一个对象参数的状态
    • 一个方法不能让对象参数引用一个新的对象

    展开全文
  • 虽然这个问题根本就没有在问“Java是不是值传递”,但是看完其它答案发现,如果不先解释清楚到底什么值传递什么是引用传递,后面的好处也无从谈起。只关心好处的请拉到最后。 第一种误解是:Java是引用传递。...


    第一篇:http://www.cnblogs.com/clara/archive/2011/09/17/2179493.html

    Java中的值传递和引用传递

    当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 
        答:是值传递。Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用一个副本。指向同一个对象,对象的内容可以在被调用的方法中改变,但对象的引用(不是引用的副本)是永远不会改变的。


    Java参数,不管是原始类型还是引用类型,传递的都是副本(有另外一种说法是传值,但是说传副本更好理解吧,传值通常是相对传址而言)。

        如果参数类型是原始类型,那么传过来的就是这个参数的一个副本,也就是这个原始参数的值,这个跟之前所谈的传值是一样的。如果在函数中改变了副本的 值不会改变原始的值.
        如果参数类型是引用类型,那么传过来的就是这个引用参数的副本,这个副本存放的是参数的地址。如果在函数中没有改变这个副本的地址,而是改变了地址中的 值,那么在函数内的改变会影响到传入的参数。如果在函数中改变了副本的地址,如new一个,那么副本就指向了一个新的地址,此时传入的参数还是指向原来的 地址,所以不会改变参数的值。

    例:
    复制代码
     1 public class ParamTest {
     2     public static void main(String[] args){
     3           /**
     4            * Test 1: Methods can't modify numeric parameters
     5            */
     6          System.out.println("Testing tripleValue:");
     7           double percent = 10;
     8           System.out.println("Before: percent=" + percent);
     9           tripleValue(percent);
    10           System.out.println("After: percent=" + percent);
    11 
    12           /**
    13            * Test 2: Methods can change the state of object parameters
    14            */
    15           System.out.println("\nTesting tripleSalary:");
    16           Employee harry = new Employee("Harry", 50000);
    17           System.out.println("Before: salary=" + harry.getSalary());
    18           tripleSalary(harry);
    19           System.out.println("After: salary=" + harry.getSalary());
    20 
    21           /**
    22            * Test 3: Methods can't attach new objects to object parameters
    23            */
    24           System.out.println("\nTesting swap:");
    25           Employee a = new Employee("Alice", 70000);
    26           Employee b = new Employee("Bob", 60000);
    27           System.out.println("Before: a=" + a.getName());
    28           System.out.println("Before: b=" + b.getName());
    29           swap(a, b);
    30           System.out.println("After: a=" + a.getName());
    31           System.out.println("After: b=" + b.getName());
    32     }
    33 
    34     private static void swap(Employee x, Employee y) {
    35         Employee temp = x;
    36         x=y;
    37         y=temp;
    38         System.out.println("End of method: x=" + x.getName());
    39         System.out.println("End of method: y=" + y.getName());
    40     }
    41 
    42     private static void tripleSalary(Employee x) {
    43         x.raiseSalary(200);
    44         System.out.println("End of method: salary=" + x.getSalary());
    45     }
    46 
    47     private static void tripleValue(double x) {
    48         x=3*x;
    49         System.out.println("End of Method X= "+x);
    50     }
    51 }
    复制代码

      显示结果:

    复制代码
    Testing tripleValue:
    Before: percent=10.0
    End of Method X= 30.0
    After: percent=10.0
    
    Testing tripleSalary:
    Before: salary=50000.0
    End of method: salary=150000.0
    After: salary=150000.0
    
    Testing swap:
    Before: a=Alice
    Before: b=Bob
    End of method: x=Bob  //可见引用的副本进行了交换
    End of method: y=Alice
    After: a=Alice  //引用本身没有交换
    After: b=Bob
    复制代码


    第二篇:图解更清楚

    今天,我在一本面试书上看到了关于java的一个参数传递的问题:

    写道
    java中对象作为参数传递给一个方法,到底是值传递,还是引用传递?

     我毫无疑问的回答:“引用传递!”,并且还觉得自己对java的这一特性很是熟悉!

    结果发现,我错了!

    答案是:

    值传递!Java中只有按值传递,没有按引用传递!

     

    回家后我就迫不及待地查询了这个问题,觉得自己对java这么基础的问题都搞错实在太丢人!

     

    综合网上的描述,我大概了解了是怎么回事,现在整理如下,如有不对之处望大神提出!

     

    先来看一个作为程序员都熟悉的值传递的例子:

     

    Java代码  收藏代码
    1. ... ...  
    2. //定义了一个改变参数值的函数  
    3. public static void changeValue(int x) {  
    4. x = x *2;  
    5. }  
    6. ... ...  
    7. //调用该函数  
    8. int num = 5;  
    9. System.out.println(num);  
    10. changeValue(num);  
    11. System.out.println(num);  
    12. ... ...  

     

    答案显而易见,调用函数changeValue()前后num的值都没有改变。

     

    由此做一个引子,我用图表描绘一个值传递的过程:

     

    num作为参数传递给changeValue()方法时,是将内存空间中num所指向的那个存储单元中存放的值,即"5",传送给了changeValue()方法中的x变量,而这个x变量也在内存空间中分配了一个存储单元,这个时候,就把num的值5传送给了这个存储单元中。此后,在changeValue()方法中对x的一切操作都是针对x所指向的这个存储单元,与num所指向的那个存储单元没有关系了!

    自然,在函数调用之后,num所指向的存储单元的值还是没有发生变化,这就是所谓的“值传递”!值传递的精髓是:传递的是存储单元中的内容,而非地址或者引用!

     

    接下来,就来看java中的对象参数是怎么传递的:

    同样,先给出一段代码:

    Java代码  收藏代码
    1. ... ...  
    2. class person {  
    3. public static String name = "Jack";  
    4. ... ...  
    5. }  
    6. ... ...  
    7. //定义一个改变对象属性的方法  
    8. public static void changeName(Person p) {  
    9. p.name = "Rose";  
    10. }  
    11. ... ...  
    12. public static void main(String[] args) {  
    13. //定义一个Person对象,person是这个对象的引用  
    14. Person person = new Person();  
    15. //先显示这个对象的name属性  
    16. System.out.println(person.name);  
    17. //调用changeName(Person p)方法  
    18. changeName(person);  
    19. //再显示这个对象的name属性,看是否发生了变化  
    20. System.out.println(person.name);  
    21. }  

     

     答案应该大家都心知肚明:

    第一次显示:“Jack”

    第二次显示:“Rose”

     

    方法用了一个对象参数,该对象内部的内容就可以改变,我之前一直认为应该是该对象复制了一个引用副本给调用函数的参数,使得该方法可以对这个对象进行操作,其实是错了!

    http://www.cnblogs.com/clara/archive/2011/09/17/2179493.html 写道
    Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用一个副本。指向同一个对象,对象的内容可以在被调用的方法中改变,但对象的引用(不是引用的副本)是永远不会改变的。 

     

    为什么这里是“值传递”,而不是“引用传递”?

    我还是用图表描绘比较能解释清楚:

     

     

    主函数中new 了一个对象Person,实际分配了两个对象:新创建的Person类的实体对象,和指向该对象的引用变量person。

    【注意:在java中,新创建的实体对象在堆内存中开辟空间,而引用变量在栈内存中开辟空间】

    正如如上图所示,左侧是堆空间,用来分配内存给新创建的实体对象,红色框是新建的Person类的实体对象,000012是该实体对象的起始地址;而右侧是栈空间,用来给引用变量和一些临时变量分配内存,新实体对象的引用person就在其中,可以看到它的存储单元的内容是000012,记录的正是新建Person类实体对象的起始地址,也就是说它指向该实体对象。

    这时候,好戏上台了:

    调用了changeName()方法,person作为对象参数传入该方法,但是大家特别注意,它传入的是什么!!!person引用变量将自己的存储单元的内容传给了changeName()方法的p变量!也就是将实体对象的地址传给了p变量,从此,在changeName()方法中对p的一切操作都是针对p所指向的这个存储单元,与person引用变量所指向的那个存储单元再没有关系了!

    回顾一下上面的一个值传递的例子,值传递,就是将存储单元中的内容传给调用函数中的那个参数,这里是不是异曲同工,是所谓“值传递”,而非“引用传递”!!!

     

    那为什么对象内部能够发生变化呢?

    那是因为:p所指向的那个存储单元中的内容是实体对象的地址,使得p也指向了该实体对象,所以才能改变对象内部的属性!

    这也是我们大多数人会误以为是“引用传递”的终极原因!!!









    第三篇:为什么 Java 只有值传递,但 C# 既有值传递,又有引用传递,这种语言设计有哪些好处?


    先强调这个问题前半句是真命题。说问题逻辑有问题,说一切都是值传递,都是没理解什么叫引用传递和值传递。


    虽然这个问题根本就没有在问“Java是不是值传递”,但是看完其它答案发现,如果不先解释清楚到底什么是值传递,什么是引用传递,后面的好处也无从谈起。只关心好处的请拉到最后。


    第一种误解是:Java是引用传递。(这么理解的人,大体会解释说Java的形参是对象的引用所以才叫引用传递。这个解释的错误在于:引用传递这个词不是这个意思,这个词是形容调用方式,而不是参数本质的类型的。所以,即使有人因为明白引用本身也是个值,然后觉得Java其实是值传递了,这种理解也是错的。你这种理解,叫“传递的是值”,而非“值传递”。后面展开。)

    第二种误解是:值类型是值传递,引用类型用的是引用传递。

    第三种误解是:认为所有的都是值传递,因为引用本质上也是个值,本质就是个指针嘛。

    第四种误解是:常出现在C++程序员中,声明的参数是引用类型的,就是引用传递;声明的参数是一般类型或指针的就是值传递。(也有人把指针归为引用传递,其实它比较特殊,无论你归哪边都是错的。)


    值传递与引用传递,在计算机领域是专有名词,如果你没有专门了解过,一般很难自行悟出其含义。而且在理解下面的解释时,请不要把任何概念往你所熟悉的语言功能上套。很容易产生误解。比如Reference,请当个全新的概念,它和C#引用类型中的引用,和C++的&,一点儿关系都没有。


    值传递和引用传递,属于函数调用时参数的求值策略(Evaluation Strategy),这是对调用函数时,求值和传值的方式的描述,而非传递的内容的类型(内容指:是值类型还是引用类型,是值还是指针)。值类型/引用类型,是用于区分两种内存分配方式,值类型在调用栈上分配,引用类型在堆上分配。(不要问我引用类型里定义个值类型成员或反之会发生什么,这不在这个本文的讨论范畴内,而且你看完之后,你应该可以自己想明白)。一个描述内存分配方式,一个描述参数求值策略,两者之间无任何依赖或约束关系。


    在函数调用过程中,调用方提供实参,这些实参可以是常量:

    Call(1);

    也可以是变量:

    Call(x);

    也可以是他们的组合:

    Call(2 * x + 1);

    也可以是对其它函数的调用:

    Call(GetNumber());

    但是所有这些实参的形式,都统称为表达式(Expression)。求值(Evaluation)即是指对这些表达式的简化并求解其值的过程。

    求值策略(值传递和引用传递)的关注的点在于,这些表达式在调用函数的过程中,求值的时机、值的形式的选取等问题。求值的时机,可以是在函数调用前,也可以是在函数调用后,由被调用者自己求值。这里所谓调用后求值,可以理解为Lazy Load或On Demand的一种求值方式。


    而且,除了值传递和引用传递,还有一些其它的求值策略。这些求值策略的划分依据是:求值的时机(调用前还是调用中)和值本身的传递方式。详见下表:


    <img src="https://pic4.zhimg.com/9d4d1d25add61af4442cae8069651e67_b.jpg" data-rawwidth="524" data-rawheight="101" class="origin_image zh-lightbox-thumb" width="524" data-original="https://pic4.zhimg.com/9d4d1d25add61af4442cae8069651e67_r.jpg">

    看到这里的名传递,可能就有人联想到C++里的别名(alias),其实也是两码事儿。语言层直接支持名传递的语言很不主流,但是在C#中,名传递的行为可以用Func<T>来模拟,说到这儿应该能大概猜出名传递的大致行为了。不过这不是重点,重点是值传递和引用传递。上面给出的传值方式的表述有些单薄,下表列出了一些二者在行为表象上的区别。

    &amp;lt;img src=&quot;https://pic1.zhimg.com/47590cd61b19a99dbe227b470e016fa0_b.jpg&quot; data-rawwidth=&quot;474&quot; data-rawheight=&quot;73&quot; class=&quot;origin_image zh-lightbox-thumb&quot; width=&quot;474&quot; data-original=&quot;https://pic1.zhimg.com/47590cd61b19a99dbe227b470e016fa0_r.jpg&quot;&amp;gt;

    这里的改变不是指mutate, 而是change,指把一个变量指向另一个对象,而不是指仅仅改变属性或是成员什么的(如Java,所以说Java是Pass by value,原因是它调用时Copy,实参不能指向另一个对象,而不是因为被传递的东西本质上是个Value,这么讲计算机上什么不是Value?)。


    这些行为,与参数类型是值类型还是引用类型无关。对于值传递,无论是值类型还是引用类型,都会在调用栈上创建一个副本,不同是,对于值类型而言,这个副本就是整个原始值的复制。而对于引用类型而言,由于引用类型的实例在堆中,在栈上只有它的一个引用(一般情况下是指针),其副本也只是这个引用的复制,而不是整个原始对象的复制。


    这便引出了值类型和引用类型(这不是在说值传递)的最大区别:值类型用做参数会被复制,但是很多人误以为这个区别是值类型的特性。其实这是值传递带来的效果,和值类型本身没有关系。只是最终结果是这样。


    求值策略定义的是函数调用时的行为,并不对具体实现方式做要求,但是指针由于其汇编级支持的特性,成为实现引用传递方式的首选。但是纯理论上,你完全可以不用指针,比如用一个全局的参数名到对象地址的HashTable来实现引用传递,只是这样效率太低,所以根本没有哪个编程语言会这样做。(自己写来玩玩的不算)


    综上所述,对于Java的函数调用方式最准确的描述是:参数藉由值传递方式,传递的值是个引用。(句中两个“值”不是一个意思,第一个值是evaluation result,第二个值是value content)


    由于这个描述太绕,而且在字面上与Java总是传引用的事实冲突。于是对于Java,Python、Ruby、JavaScript等语言使用的这种求值策略,起了一个更贴切名字,叫Call by sharing。这个名字诞生于40年前。


    前面讨论了各种求值策略的内涵。下面以C++为例:

    1. void ByValue(int a)  
    2. {  
    3.     a = a + 1;  
    4. }  
    5.   
    6. void ByRef(int& a)  
    7. {  
    8.     a = a + 1;  
    9. }  
    10.   
    11. void ByPointer(int* a)  
    12. {  
    13.     *a = *a + 1;  
    14. }  
    15. int main(int argv, char** args)  
    16. {  
    17.     int v = 1;  
    18.     ByValue(v);  
    19.     ByRef(v);  
    20.   
    21.     // Pass by Reference  
    22.     ByPointer(&v);  
    23.   
    24.     // Pass by Value  
    25.     int* vp = &v;  
    26.     ByPointer(vp);  
    27. }  

    Main函数里的前两种方式没有什么好说,第一个是值传递,第二个函数是引用传递,但是后面两种,同一个函数,一次调用是Call by reference, 一次是Call by value。因为:


    ByPointer(vp); 没有改变vp,其实是无法改变。


    ByPointer(&v); 改变了v。(你可能会说,这传递的其实是v的地址,而ByPointer无法改变v的地址,所以这是Call by value。这听上去可以自圆其说,但是v的地址,是个纯数据,在调用的方代码中并不存在,对于调用者而言,只有v,而v的确被ByPointer函数改了,这个结果,正是Call by reference的行为。从行为考虑,才是求值策略的本意。如果把所有东西都抽象成值,从数据考虑问题,那根本就没有必要引入求值策略的概念去混淆视听。


    请体会一下,应该就明白上面一直在说的调用的行为的意思。


    C语言不支持引用,只支持指针,但是如上文所见,使用指针的函数,不能通过签名明确其求值策略。C++引入了引用,它的求值策略可以确定是Pass by reference。于是C++的一个奇葩的地方来了,它语言本身(模拟的不算,什么都能模拟)支持Call by value和Call by reference两种求值策略,但是却提供了三种语法去做这俩事儿。


    C#的设计就相对合理,函数声明里,有ref/out,就是引用传递,没有ref/out,就是值传递,与参数类型无关。


    不过如果观察一下void ByRef(int& a)和void ByPointer(int* a)所生成的汇编代码,会发现在一定条件下其实是一样的。都是这个样子:

    ; 12   : {
    
    	push	ebp
    	mov	ebp, esp
    	sub	esp, 192				; 000000c0H
    	push	ebx
    	push	esi
    	push	edi
    	lea	edi, DWORD PTR [ebp-192]
    	mov	ecx, 48					; 00000030H
    	mov	eax, -858993460				; ccccccccH
    	rep stosd
    
    ; 13   : 	*a = *a + 1;
    
    	mov	eax, DWORD PTR _a$[ebp]
    	mov	ecx, DWORD PTR [eax]
    	add	ecx, 1
    	mov	edx, DWORD PTR _a$[ebp]
    	mov	DWORD PTR [edx], ecx
    

    调用方的代码也是一样的。代码就不贴了。


    这两种传递方式说完了,下面回到正题说好处。问题中“这种”指代不明,且认为是Java。


    支持多种求值策略可以给语言带来更高的灵活性,但是同时也需要一个“灵活”的人来良好地驾驭。Java通过牺牲这种价值不大还可能带来问题的灵活性,带来了语言自身语法一致性、逻辑鲁棒性及更容易学习等多个好处。


    不仅仅Java和C#,每个语言,在设计时都需要在这些特性间做出自己独特的取舍来体现自己的设计理念,并适应不同人,不同使用环境的要求。虽然说没有什么功能是一个语言可以做,而另一个语言做不了的。但是每个语言,都有它最适合的范畴与不适合的范畴。



    作者:Hugo Gu
    链接:https://www.zhihu.com/question/20628016/answer/28970414
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    
    
    展开全文
  • 为什么Java只有值传递

    千次阅读 2019-06-11 09:24:03
    参考Java核心技术卷4.5方法参数 ...写了三个例子,讲述了为什么Java只有值传递。 例子A : public static void main(String[] args) { int i=1; int j=2; //交换两个值 swap(i, j); System....

    参考Java核心技术卷4.5方法参数

    最开始以为Java有值传递和引用传递,在JavaGuide中看到一个标题为什么Java中只有值传递?写了三个例子,讲述了为什么Java只有值传递。

    例子A :

    public static void main(String[] args) {
    		int i=1;
    		int j=2;
    		//交换两个值
    		swap(i, j);	
    		System.out.println("i="+i);
    	    System.out.println("j="+j);
    	}
    
    	public static void swap(int x, int y) {
          int temp=x;
          x=y;
          y=temp;
          System.out.println("x="+x);
          System.out.println("y="+y);
    	}
    
    结果为:x=2
           y=1
           i=1
           j=2
    

    这个例子可以看出 最简单的值传递 并不会影响到外面的i,j 因为x,y是拷贝的i,j 所以在swap方法中并不会影响到外面。

     

     

    例子B:

    public static void main(String[] args) {
    		Product p1=new Product();
    		p1.setId(1);
    		p1.setName("纯牛奶");
    		p1.setPrice(new BigDecimal("3.5"));
    		System.out.println("修改前"+p1);
    		name(p1);		
    		System.out.println("-----------------------------");
    		System.out.println("修改后"+p1);
    	}
    	public static void name(Product x) {
    		x.setId(4);			
    	}
    
    
    修改前Product [id=1, name=纯牛奶, price=3.5]
    -----------------------------
    修改后Product [id=4, name=纯牛奶, price=3.5]
    

    这里乍一看确实是引用传递,我最开始也以为通过对象作为参数就是引用传递,传递的是地址。但是请看第三个例子。

     

    例子C:这里 我定义了p1 p2两个对象进行交换

    	public static void main(String[] args) {
    		Product p1=new Product();
    		p1.setId(1);
    		p1.setName("纯牛奶");
    		p1.setPrice(new BigDecimal("3.5"));
    		Product p2=new Product();
    		p2.setId(2);
    		p2.setName("水杯");
    		p2.setPrice(new BigDecimal("4.5"));
    		name(p1,p2);
    		System.out.println("-----------------------------");
    		System.out.println(p1);
    		System.out.println(p2);
    
    	}
    	public static void name(Product x,Product y) {
    		Product temp =x;
    		x=y;
    		y=temp;
    		System.out.println(x);
    		System.out.println(y);							
    	}
    
      结果:
    ------------方法执行前-----------------
    Product [id=1, name=纯牛奶, price=3.5]
    Product [id=2, name=水杯, price=4.5]
    ------------方法执行后-----------------
    Product [id=2, name=水杯, price=4.5]
    Product [id=1, name=纯牛奶, price=3.5]
    ------------方法结束-----------------
    Product [id=1, name=纯牛奶, price=3.5]
    Product [id=2, name=水杯, price=4.5]
    

    这里如果我们坚持 对象是引用传递的话 那么p1 和 p2在方法结束后应该会交换地址 但是并没有。这里可以证明Java中只有值传递

    如果还不懂  不能理解的话 可以下载该书籍看下 链接:

    https://pan.baidu.com/s/1zg54GW9YuGMCjVtk_xkWMg 
    提取码:p5m4 
    复制这段内容后打开百度网盘手机App,操作更方便哦

     

     

    展开全文
  • java中的参数传递(只有值传递没有引用传递)

    万次阅读 多人点赞 2019-07-31 19:25:14
    Java只有传值调用(值传递),没有传址调用(址传递或者引用传递)。所以在java方法中改变参数的值是不会改变原变量的值的,但为什么改变引用变量的属性值却可以呢?请看下面的解答。 java中的数据类型 Java中...
  • 为什么Java只有值传递
  • 为什么java只有值传递? 如果你学的第一门程序语言是java可能对这个传递方式没有那么敏感,如果学了c或c++,然后再学java,那么可能对这个问题会感到困惑。 1.值传递与引用传递的概念 在将传递方式之前先理解...
  • 首先,我们得先知道什么值传递什么叫引用传递,知道这个才能理解Java到底如何做的。若想理解这两种传递需要先理解形式参数和实际参数两个概念 形式参数: 定义函数时使用的参数,用来接收函数传入参数,比如我们...
  • 主要介绍了为什么 Java只有值传递?下面我们来简单了解一下吧
  • Java中当传递的参数是对象时,其实还是值传递的,只不过对于对象参数,值的内容是对象的引用。当调用方法改变对象引用(即传递的值)时,如指向另一个对象时,原对象是不发生任何变换的,而当改变的不是传递过来的值...
  • 为什么java只有值传递

    千次阅读 2018-07-10 15:43:09
    我们来看看上面是值传递和引用传递首先要知道基本数据类型的值以及引用类型的引用是存放在堆中的,引用类型实际的数据是存放在栈中的对于8...对于引用类型为什么说是值传递,我贴个网上看到的代码class Student { ...
  • 值传递 当一个对象被当作参数传递到一个方法...为什么 Java只有值传递 首先回顾一下在程序设计语言中有关将参数传递给方法(或函数)的一些专业术语。按值调用(call by value)表示方法接收的是调用者提供的值,而按
  • 文章目录Java 为什么只有值传递一、参数传递给方法的方式二、Java 总是按值调用三、总结 Java 为什么只有值传递 Java值传递 一、参数传递给方法的方式 在程序设计语言中,参数传递给方法的方式有两种: 按值调用...
  • 首先,我们得先知道什么值传递什么叫引用传递,知道这个才能理解Java到底如何做的。若想理解这两种传递需要先理解形式参数和实际参数两个概念 形式参数:定义函数时使用的参数,用来接收函数传入参数,比如我们...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 412
精华内容 164
关键字:

为什么java只有值传递

java 订阅