Java中变量的传值和传引用

Java中变量的传值和传引用

1.Java中变量的基本类型

  为了了解Java中参数的传值和传引用,我们需要先知道Java中参数的基本类型,Java中数据类型分为两大类,基本类型和对象类型。相应的,变量也有两种类型:基本类型和引用类型。
基本类型的变量保存原始值,即它代表的值就是数值本身;而引用类型的变量保存引用值,"引用值"指向内存空间的地址,代表了某个对象的引用,而不是对象本身,对象本身存放在这个引用值所表示的地址的位置。
  基本类型包括:byte,short,int,long,char,float,double,Boolean,returnAddress,
  引用类型包括:类类型,接口类型和数组。
相应的,变量也有两种类型:基本类型和引用类型。
方法的参数分为实际参数,和形式参数。

形式参数:定义方法时写的参数。
实际参数:调用方法时写的具体数值。

一般情况下,在数据做为参数传递的时候,基本数据类型是值传递,引用数据类型是引用传递(地址传递)。

2.传值和传引用的区别

在了解传值和传引用之前,我们需要先了解Java内存区域的划分。如图在这个数据区中,它由以下几部分组成:
1 . 虚拟机栈2. 堆3. 程序计数器4. 方法区5. 本地方法栈

在这里插入图片描述
堆、栈、静态方法区、常量区相应地,每个存储区域都有自己的内存分配策略:堆式、栈式、静态
前面已经介绍过形参和实参,也介绍了数据类型以及数据在内存中的存储形式,接下来,就是文章的主题:值传递和引用的传递。

值传递

值传递:
在方法被调用时,实参通过形参把它的内容副本传入方法内部,此时形参接收到的内容是实参值的一个拷贝,因此在方法内对形参的任何操作,都仅仅是对这个副本的操作,不影响原始值的内容。

1public static void valueCrossTest(int age,float weight){
2    System.out.println("传入的age:"+age);
3    System.out.println("传入的weight:"+weight);
4    age=33;
5    weight=89.5f;
6    System.out.println("方法内重新赋值后的age:"+age);
7    System.out.println("方法内重新赋值后的weight:"+weight);
8    }
9
10//测试
11public static void main(String[] args) {
12        int a=25;
13        float w=77.5f;
14        valueCrossTest(a,w);
15        System.out.println("方法执行后的age:"+a);
16        System.out.println("方法执行后的weight:"+w);
17}

结果

1传入的age:25
2传入的weight:77.5
3
4方法内重新赋值后的age:33
5方法内重新赋值后的weight:89.5
6
7方法执行后的age:25
8方法执行后的weight:77.5

例子中
int a=10;中的a在被调用之前就已经创建并初始化,在调用func方法时,他被当做参数传入,所以这个a是实参。
而func(int a)中的a只有在func被调用时才开始,而在func调用结束之后,它也随之被释放掉,,所以这个a是形参。

引用传递

引用传递:
”引用”也就是指向真实内容的地址值,在方法调用时,实参的地址通过方法调用被传递给相应的形参,在方法体内,形参和实参指向通愉快内存地址,对形参的操作会影响的真实内容。
举个关于马云和马化腾的例子

public class Person {  
private String name;  
private int 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 static void PersonCrossTest(Person person) {
  System.out.println("传入的person的name:" + person.getName());
  person.setName("我是马云");
  System.out.println("方法内重新赋值后的name:" + person.getName());
 } // 测试
 public static void main(String[] args) {
  Person p = new Person();
  p.setName("我是马化腾");
  p.setAge(45);
  PersonCrossTest(p);
  System.out.println("方法执行后的name:" + p.getName());
 }
}

输出结果

传入的person的name:我是马化腾
方法内重新赋值后的name:我是马云
方法执行后的name:我是马云

可以看出,person经过personCrossTest()方法的执行之后,内容发生了改变,这印证了上面所说的“引用传递”,对形参的操作,改变了实际对象的内容。

下面我们对上面的例子稍作修改,加上一行代码

public static void PersonCrossTest(Person person) {
  System.out.println("传入的person的name:" + person.getName());
  person=new Person();//加多此行代码
  person.setName("我是马云");
  System.out.println("方法内重新赋值后的name:" + person.getName());
 }

结果就变成了

传入的person的name:我是马化腾
方法内重新赋值后的name:我是马云
方法执行后的name:我是马化腾

为什么这次的输出和上次的不一样了呢?
因为当执行到PersonCrossTest()方法时,因为方法内有这么一行代码:

1person=new Person();

此时堆内另外开辟一块内存来存储new Person(),假如真的是引用传递,那么由上面讲到:引用传递中形参实参指向同一个对象,形参的操作会改变实参对象的改变。可以推出:实参也应该指向了新创建的person对象的地址,所以在执行PersonCrossTest()结束之后,最终输出的应该是后面创建的对象内容。然而实际上,最终的输出结果却跟我们推测的不一样,最终输出的仍然是一开始创建的对象的内容。由此可见:引用传递,在Java中并不存在。但是有人会疑问:为什么第一个例子中,在方法内修改了形参的内容,会导致原始对象的内容发生改变呢?这是因为:无论是基本类型和是引用类型,在实参传入形参时,都是值传递,也就是说传递的都是一个副本,而不是内容本身。

3.总结

结合上面的分析,关于值传递和引用传递可以得出这样的结论:
(1)基本数据类型传值,对形参的修改不会影响实参;
(2)引用类型传引用,形参和实参指向同一个内存地址(同一个对象),所以对参数的修改会影响到实际的对象;
(3)String, Integer, Double等immutable的类型特殊处理,可以理解为传值,最后的操作不会修改实参对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值