• 为什么说java只有值传递?


    如果你学的第一门程序语言是java可能对这个传递方式没有那么敏感,如果学了c或c++,然后再学java,那么可能对这个问题会感到困惑。

    1.值传递与引用传递的概念

    在将传递方式之前先理解一下形参与实参。

    形式参数:是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数。

    实际参数:在调用有参函数时,主调函数和被调函数之间有数据传递关系。在主调函数中调用一个函数时,函数名后面括号中的参数称为“实际参数”。

    可以这么理解:形参是实参的抽象,实参是调用时的参数,形参是定义函数的参数

    值传递:方法调用时,实际参数把它的值传递给对应的形式参数,函数接收的是原始值的一个copy,此时内存中存在两个相等的基本类型,即实际参数和形式参数,后面方法中的操作都是对形参这个值的修改,不影响实际参数的值。

    引用传递:是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

    划重点:值传递和引用传递的主要区别

    值传递

    引用传递

    创建副本,在函数体中不能改变原来的值

    不创建副本,在在函数体中不能改变原来的值

     创建副本的含义看图:

    创建副本也就是说,把要调用的实参先拷贝一份出来,然后用拷贝的那一份传进函数体内。不创建副本时,不会发生copy这个步骤。

    举个值传递的栗子:

     1 public class Test01 {
     2     public static void main(String[] args) {
     3         int a=1,b=2;
     4         swap(a, b);
     5         System.out.println("a="+a);
     6         System.out.println("b="+b);
     7     }
     8     public static void swap(int a,int b) {
     9         int temp=a;
    10         a=b;
    11         b=temp;
    12     }
    13 }

    结果:

    1 a=1
    2 b=2

    上面栗子中,在函数中让实现a,b交换,但调用函数后,输出的结果仍然是a,b原来的值,说明函数体中的操作并不能影响a,b在函数体外的值。

    引用传递的栗子就不测试了,有兴趣的话可以用c++来测试,参数为定义为别名或指针时,在c++中是引用传递。

    误区:传递的参数如果是普通类型,那就是值传递,如果是对象,那就是引用传递。这是错误的!!!!!

    2.java中的值传递

     在java中,无论参数是基本类型,还是引用数据类型,都是值传递方式。下面来举个引用数据类型的参数,基本数据类型传参的栗子上面已经有了。

     1 public class Test01 {
     2     public static void  swap(Student st1,Student st2) {
     3         Student temp=st1;
     4         st1=st2;
     5         st2=temp;
     6     }
     7         
     8     public static void main(String[] args) {
     9         Student st1=new Student("张三",20);
    10         Student st2=new Student("李四",20);
    11         swap(st1, st2);
    12         System.out.println("st1:"+st1);
    13         System.out.println("st2:"+st2);
    14 }

    结果:

    1 st1:Student [name=张三, age=20]
    2 st2:Student [name=李四, age=20]

    例子中,st1和st2的所指向的对象并没有发生改变。

    这时候,你可能会问,既然java是值传递,那么实参会发生拷贝,那拷贝的是什么东西呢?答案是:拷贝的是对象在堆中的地址。来个栗子来验证一下:

     1 public class Test01 {
     2     public static void  print(Student stu1,Student stu2) {
     3         Student temp=stu1;
     4         stu1=stu2;
     5         stu2=temp;
     6         System.out.println("在函数体中交换后打印stu1:  "+stu1);
     7         System.out.println("在函数体中交换后打印stu2:  "+stu2);
     8     }
     9         
    10     public static void main(String[] args) {
    11         Student stu1=new Student("stu1",20);
    12         Student stu2=new Student("stu2",30);
    13         print(stu1, stu2);
    14     }
    15 }

    结果:

    1 在函数体中交换后打印stu1:  Student [name=stu2, age=30]
    2 在函数体中交换后打印stu2:  Student [name=stu1, age=20]

    从结果中可以看出,在函数体中stu1stu2所指向的对象确实是发生了改变,这是因为在值传递的过程中拷贝了他们在堆中的地址。

    来看看他们在内存中是怎么样的:

    这时候你可能会问,既然java的值传递是拷贝地址,那我能不能改变地址所指向的内容?答案是:当然可以

    1     public static void  changeInf(Student stu) {
    2         stu.setName("我改名字了");
    3     }
    4         
    5     public static void main(String[] args) {
    6         Student stu=new Student("张三",18);
    7         changeInf(stu);
    8         System.out.println(stu);
    9     }

    结果:

    1 Student [name=我改名字了, age=18]

    对象内容改变了

    结论:java中只有值传递,这可能是因为java没有指针和别名引用的原因吧。

  • 相关阅读:
    ios专题 - CocoaPods - 初次体验
    ios专题 - CocoaPods - 安装
    Objective-C浅拷贝和深拷贝
    支付宝交互流程
    UITabBar的隐藏
    iOS-容易造成循环引用的三种场景
    FMDB 的基本操作
    Swap file ".Podfile.swp" already exists!
    将UIImage保存成JPG或PNG格式存储在本地
    UI常用控件的一些属性
  • 原文地址:https://www.cnblogs.com/ironHead-cjj/p/11366888.html
Copyright © 2020-2023  润新知