• Java中值传递和引用传递


      值传递和引用传递问题一般是相对函数而言的,那说到函数就得提到有关参数传递给方法的两个专业术语:按值调用(call by value)和 按引用调用(call by reference)。

      按值调用是说方法接收的是调用者提供的值,而按引用调用则是方法接收的是调用者提供的变量地址(用C语言的话来说就是指针,当然java并没有指针的概念)。

      这里需要特别注意的是一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值,这是按值调用与引用调用的根本区别,如果没理解后面会有例子解释说明。

      其实java中并不存在引用调用,因为java程序设计语言确实是采用了按值调用,即call by value。也就是说方法得到的是所有参数值的一个拷贝,方法并不能修改传递给它的任何参数变量的内容。代码案例:

     1 public class CallByValue {
     2 
     3     private static int Y=5;
     4 
     5     public static void updateValue(int value){
     6         value = 2 * value;
     7     }
     8 
     9     public static void main(String[] args) {
    10         System.out.println("调用前Y的值:"+Y);
    11         updateValue(Y);
    12         System.out.println("调用后Y的值:"+Y);
    13     }
    14 
    15 }
    调用前Y的值:5
    调用后Y的值:5

      然而发现Y的值并没有改变

    分析:

    1. value被初始化为Y值的一个拷贝(也就是5)
    2. value被乘以2后等于10,但注意此时Y的值仍为5
    3. 方法调用结束后,参数变量value不再使用,被回收。

    总结:

      当传递方法参数类型为基本数据类型(数字以及布尔值)时,一个方法是不可能修改一个基本数据类型的参数。

      然而在java中除了基本数据类型外还有引用数据类型,接下来看它的传递情况。

    //声明一个User类
    public class User {
        private String name;
        private int age;
        public User(String name, int age) {
            this.name=name;
            this.age=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;
        }
    }

    测试代码:

    public class CallByValue {
        private static User user=null;
        public static void updateUser(User student){
            student.setName("YJ");
            student.setAge(20);
        }
    
    
        public static void main(String[] args) {
            user = new User("Luzun",18);
            System.out.println("调用前user的值:"+user.toString());
            updateUser(user);
            System.out.println("调用后user的值:"+user.toString());
        }
    }
    调用前user的值:User [name=Luzun, age=18]
    调用后user的值:User [name=YJ, age=20]

      很显然,User的值被改变了,也就是说方法参数类型如果是引用类型的话,引用类型对应的值将会被修改。

    分析:

    1. student变量被初始化为user值的拷贝,这里是一个对象的引用。
    2. 调用student变量的set方法作用在这个引用对象上,user和student同时引用的User对象内部值被修改。
    3. 方法结束后,student变量不再使用,被释放,而user还是没有变,依然指向User对象。

    总结:

      当传递方法参数类型为引用数据类型时,一个方法将修改一个引用数据类型的参数所指向对象的值。

      通过上面的测试你可能就会觉得java同时拥有按值调用和按引用调用,然而可惜的是这是有误导性的,虽然上面引用传递表面上体现了按引用调用现象,但是java中确实只有按值调用而没有按引用调用。下面再进行一个测试:

    public class CallByValue {
        private static User user=null;
        private static User stu=null;
    
           public static void swap(User x,User y){
            User temp =x;
            x=y;
            y=temp;
        }
    public static void main(String[] args) { user = new User("teacher",28); stu = new User("student",16); System.out.println("调用前user的值:"+teacher.toString()); System.out.println("调用前stu的值:"+student.toString()); swap(teacher,student); System.out.println("调用后user的值:"+teacher.toString()); System.out.println("调用后stu的值:"+student.toString()); } }

      可以通过一个swap函数来交换两个变量teacher和student的值,如果是按引用调用那么一个方法可以修改传递引用所对应的变量值,也就是说如果java是按引用调用的话,那么swap方法将能够实现数据的交换,而实际运行结果:

    调用前teacher的值:User [name=teacher, age=28]
    
    调用前student的值:User [name=student, age=16]
    
    调用后teacher的值:User [name=teacher, age=28]
    
    调用后student的值:User [name=student, age=16]

      发现teacher和student的值并没有发生变化,也就是方法并没有改变存储在变量teacher和student中的对象引用。swap方法的参数x和y被初始化为两个对象引用的拷贝,这个方法交换的是这两个拷贝的值而已,最终在方法结束后x,y被丢弃,而原来的变量teacher和student仍然引用这个方法调用之前所引用的对象。这个过程也充分说明了java程序设计语言对对象采用的不是引用调用,实际上是对象引用进行的是值传递。java函数在传递引用数据类型时,也只是拷贝了引用的值罢了,之所以能修改引用数据是因为它们同时指向了一个对象,但这仍然是按值调用而不是引用调用。

  • 相关阅读:
    Android Canvas save() restore()
    Android Custom View
    Android Canvas drawArc()
    每日一记--2014.9.15
    每日一记--2014.9.14
    每日一记--2014.9.13
    每日一记--2014.9.12
    每天一记--2014.9.11
    每日一记,今天开始
    java中的Iterator和Iterable
  • 原文地址:https://www.cnblogs.com/jie-y/p/10787172.html
Copyright © 2020-2023  润新知