Java面向对象基础2 - - Java中的值传递和引用传递

1. 概念

1.1 值传递和引用传递

在程序设计语言中参数传递给方法(或函数)的方式分为两种:① 按值调用(call by value),② 按引用调用(call by reference),所谓的按值调用表示方法接收的是:被调用参数提供的数值,而按引用调用则表示方法接收的是被调用参数提供的变量地址。变量地址在C语言中被称为指针,在Java中被称为引用。

Java程序设计语言采用按值调用(call by value)的方式进行参数传递,也就是说方法得到的是所有参数值的一个拷贝,方法并不能修改传递给它的任何参数变量的内容。为了更好的理解这句话,我们先了解Java中的数据类型

1.2 Java中的数据类型

在Java程序设计语言中数据类型可分为:基本数据类型和引用数据类型。其中基本数据类型的变量中存放的是该变量的值;而引用数据类型的变量中存放是该变量的引用,例如:

public class TestPet {
	public static void main(String[] args) {
		
		int a = 10;
		int arr = {1,2,3};
		Pet p = new Dog();

	}
}
class Dog Pet{
	
    String name;
	String type;
	
	public Dog() {
	
	}

	public void move() {
		System.out.println("run");
	}
}

对应的内存分析图如下:

整形数据变量a中存放的是值10;数组arr和对象p中存放的分别是引用1bd23456、23cf34452

2. Java中的数据传递

2.1. 传递参数为基本类型数据

直接上代码:

    package com.ppw.test0726;  
    /** 
     * java中的按值调用 
     * @author panpan
     */  
    public class CallByValue {   
     
        public static void main(String[] args) {  
            int x=10;
            System.out.println("调用前x的值:"+x);  
            updateValue(x);  
            System.out.println("调用后x的值:"+x);  
        }  

        public static void updateValue(int value){  
            value = 3 * value;  
        } 
          
    }  
 

程序运行结果为:

调用前x的值:10 

调用后x的值:10

我们来分析下代码执行的过程:当程序进入主函数main()以后,首先为x赋值10后执行语句System.out.println("调用前x的值:"+x),“输出调用前x的值:10”; 然后调用updatValue()函数,并将实参x的值拷贝一份传递给形参value,此时x和value值均为10,然后程序进入该函数的内部,执行value = 3 * value,value变为30,x不变仍为10,随后程序调用完updateValue()函数回到主函数,执行System.out.println("调用后x的值:"+x),输出“调用后x的值:10”。

分析程序执行过程发现:实参传递给形参的过程,就是将实参的值拷贝一份传递给形参方法内部修改的是形参value,而未对实参x做任何修改,根据value的作用域可知,当调用完updateValue()后,value的生命周期结束,被GC回收了。

 这里给大家提供一个程序代码,供大家思考:程序的输出结果是?

    package com.ppw.test;
    /** 
     * java中的按值调用 
     * @author panpan
     */  
    public class TestValue {   
     
        public static void main(String[] args) {  
            int x=10;
            System.out.println("调用前x的值:"+x);  
            updateValue(x);  
            System.out.println("调用后x的值:"+x);  
        }  

        public static void updateValue(int x){  
            x = 3 * x;  // 此处的x是updateValue中的x,与main方法中的x无关
        } 
          
    }  

总结一下:当向方法中传递的参数类型为基本数据类型(数字以及布尔值)时,这个方法是不能修改实参中的值的,本质是因为将实参中存储的值拷贝一份传递给形参,

2. 2. 传递参数为引用类型数据

直接上代码:创建一个User类

public class User {  
    private String name;  
    private int age;  
    
    public User(){
    }
    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;  
    }  
}  

创建一个测试类:

/** 
 * java中的按值调用 
 * @author panpan 
 */  
public class TestAddress {  
    private static User user=null;  
    public static void updateUser(User student){  
        student.setName("Lishen");  
        student.setAge(18);  
    }  
      
      
    public static void main(String[] args) {  
        user = new User("zhangsan",26);  
        System.out.println("调用前user的值:"+user.toString());  
        updateUser(user);  
        System.out.println("调用后user的值:"+user.toString());  
    }  
}  

运行结果为:

调用前user的值:User [name=zhangsan, age=26]

调用后user的值:User [name=Lishen, age=18]

我们分析程序代码的执行过程:当程序执行到user = new User("zhangsan", 26),会在堆内存中开辟空间用来存放对象user中的属性,并将该空间的首地址传递给user,假设地址为@1a1c1234,然后调用System.out.println("调用前user的值:"+user.toString());  输出结果“调用前user的值:User [name=zhangsan, age=26]”,在执行updateUser()时,将实参user中存储的地址传递给形参student中,即student指向user指向的地址,当在updateUser()函数中执行student.setName(Lishen)和student.setAge(18)时,student根据user提供的地址找到set方法更改了name和age属性,跳出updateUser函数后执行System.out.println("调用后user的值:"+user.toString());  输出“调用后user的值:User [name=Lishen, age=18]”。

 

 通过对程序执行过程分析,我们发现:实参传递给形参的过程,就是将实参user中存放的的地址值拷贝一份传递给形参student方法内部修改的是形参student指向的地址(user)中存放的内容(name,age),而未对实参user做任何修改,也不能堆实参user做任何修改。student之所以能修改user中属性,实际上是因为student根据user提供的地址找到了user中name和age,因此可以修改

总结:当向方法中传递的参数类型为引用数据类型时,这个方法可以修改一个引用数据类型的参数所指向对象的值

值的注意的是:Java程序语言中采用值传递,即无论传递参数的类型是引用数据类型还是基本数据类型,都是将实参中存放的值拷贝至形参中,方法不能改变实参中存放的值,对于基本数据类型这个值是基本数据类型的数值;对于引用数据类型这个值是地址。

我们在看下面这段代码,理解上面这段话,

/** 
 * java中的按值调用 
 * @author panpan 
 */  
public class CallByValue {  
    private static User user=null;  
    private static User stu=null;  
      
    /** 
     * 交换两个对象 
     * @param x 
     * @param y 
     */  
    public static void swap(User x,User y){  
        User temp =x;  
        x=y;  
        y=temp;  
    }  
      
    public static void main(String[] args) {  
        user = new User("user",26);  
        stu = new User("stu",18);  
        System.out.println("调用前user的值:"+user.toString());  
        System.out.println("调用前stu的值:"+stu.toString());  
        swap(user,stu);  
        System.out.println("调用后user的值:"+user.toString());  
        System.out.println("调用后stu的值:"+stu.toString());  
    }  
}  

运行结果为:

调用前user的值:User [name=user, age=26]

调用前stu的值:User [name=stu, age=18]

调用后user的值:User [name=user, age=26]

调用后stu的值:User [name=stu, age=18]

运行结果告诉我们user和stu的值并没有发生变化,也就是说方法并没有改变存储在变量user和stu中的对象引用。swap方法的参数x和y被初始化为两个对象引用的拷贝,这个方法交换的是这两个拷贝的值而已。在方法结束后x,y将被丢弃,而原来的变量user和stu仍然引用这个方法调用之前所引用的对象。

这个过程也充分说明了java程序设计语言对对象采用的不是引用调用,实际上是对象引用进行的是值传递,不论是传递基本数据类型还是引用数据类型,java函数只是拷贝了实参存储的值,基本数据类型的实参存储的数值,引用数据类型的实参存储的是地址,之所以形参能修改引用数据是因为形参和实参同时指向了一个对象 

边学习,边总结,此篇文章参考链接如下,如有侵权,联系删除

https://blog.csdn.net/sugar_no1/article/details/86506510

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值