• 为什么Java只有值传递?


    形参和实参

    形式参数,是在方法定义阶段,是定义某个函数时使用的参数,用于接收实参传入。例f(x,y)中x和y是形参。

    实际参数,是在方法调用阶段,是主调函数调用有参函数时,实际传递的内容。例f(3,7)中3和7是实参。

    值传递和引用传递

    值传递和引用传递不是简单地通过传递内容区分的。如果是值,就是值传递;如果是引用,就是引用传递。这一理解是不正确的。

    值传递,是指在调用函数时将实际参数复制一份传递给函数形参。此时,在函数中对形参做修改,不影响实际参数。

    引用传递,是指在调用函数时将实际参数的地址直接传递给函数形参。此时,在函数中对参数做修改,将影响实际参数。

    根本区别在于值传递会创建副本,因此函数中无法改变原始对象;引用传递不创建副本,函数中可以改变原始对象。

    通过一个经典案例讲解Java值传递

    public class ParamPassing {
        private static int intStatic = 222;
        private static String stringStatic = "old string";
        private static StringBuilder stringBuilderStatic = new StringBuilder("old stringBuilder");
    
        public static void main(String[] args) {
            // 方法调用1
            method(intStatic);
            System.out.println(intStatic);
            // 方法调用2
            method();
            System.out.println(intStatic);
            // 方法调用3
            method(stringStatic);
            System.out.println(stringStatic);
            // 方法调用4
            method(stringBuilderStatic, stringBuilderStatic);
            System.out.println(stringBuilderStatic);
        }
    
        // 方法1
        public static void method(int intStatic) {
            intStatic = 777;
        }
    
        // 方法2
        public static void method() {
            intStatic = 888;
        }
    
        // 方法3
        public static void method(String stringStatic) {
            stringStatic = "new string";
        }
    
        // 方法4
        public static void method(StringBuilder stringBuilderStatic1, StringBuilder stringBuilderStatic2) {
            stringBuilderStatic1.append(".method.first-");
            stringBuilderStatic2.append(".method.second-");
    
            // 引用重新赋值
            stringBuilderStatic1 = new StringBuilder("new stringBuilder");
            stringBuilderStatic1.append("new method's append");
        }
    }
    
    运行结果:
    222
    888
    old string
    old stringBuilder.method.first-.method.second-
    

    方法1,参数是局部变量,拷贝的变量值是777,会存入虚拟机栈中的局部变量表的第一个位置。在方法内部,根据作用于就近原则,使用局部变量的参数,操作与实参无关。而方法2,先把本地赋值的888压入虚拟机栈中的操作栈,然后给静态遍历intStatic赋值。

    
    public static void method(int);
    Code:
       0: sipush        777   // 将常量加载到操作数栈
       3: istore_0            // 将一个数值从操作数栈存储到局部变量表
       4: return              // 返回
    
    public static void method();
    Code:
       0: sipush        888
       3: putstatic     #2    // Field intStatic:I 访问类变量(static字段)
       6: return
    
    
    

    方法3,String是immutable对象,类中没有提供任何方法用来修改对象。“old string"仍然由实参持有,在方法3中,会重新new一个String对象,并把引用赋给形参。

    方法4,直接使用参数引用,可以修改对象;当对引用重新赋值后,不再影响实参。
    当stringBuilderStatic引用作为实参传递给形参stringBuilderStatic1时,此时形参是stringBuilderStatic的一个副本,两个引用共同指向StringBuilder对象所在的堆内存地址,此时对形参的任何修改都会改变对象属性。当创建新对象并赋值给stringBuilderStatic1后,该引用指向了新的内存地址,对其修改不会改变原对象的属性。

    字节码解释

    0: aload_0                 // 引用类型入栈
    1: ldc           #14       // 将常量值从常量池推到栈顶
    // String .method.first-
    3: invokevirtual #15       // 调用实例方法               
    // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    6: pop                     // 栈顶元素出栈
    
    14: new           #17      // 创建实例
    // class java/lang/StringBuilder
    17: dup                    // 赋值栈顶数值,压入栈顶
    18: ldc           #18                 
    // String new stringBuilder
    20: invokespecial #19      // 实例初始化                
    // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
    23: astore_0               // 将栈中ref引用存到局部变量表
    
    24: aload_0                // 加载局部变量到操作数栈
    25: ldc           #20      // 加载常量到操作数栈
    // String new method's append
    27: invokevirtual #15      // 调实例方法
    // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    30: pop                    // 操作数栈顶元素出栈
    31: return                 // 方法返回指令
    
    版权声明:本文为博主原创文章,未经博主允许不得转载。
  • 相关阅读:
    Socket send函数和recv函数详解
    isdigit()函数用法
    C语言的那些小秘密之字节对齐
    The Five Best Linux BitTorrent Clients
    怎么计算网站高峰期并发量和所需的带宽?
    软件需求包括3个不同的层次 业务需求、用户需求和功能需求
    右键删除选中的行总提示rowIndex
    SQL Server[转]SQL Server中临时表与表变量的区别
    面向对象的软件工程应用浅研
    OO开发思想:面向对象的开发方法(Object oriented,OO)
  • 原文地址:https://www.cnblogs.com/dtyy/p/11172925.html
Copyright © 2020-2023  润新知