前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java真的只有值传递?

Java真的只有值传递?

作者头像
一觉睡到小时候
发布2019-07-02 17:00:48
6770
发布2019-07-02 17:00:48
举报
文章被收录于专栏:国产程序员国产程序员

JAVA核心技术卷一中说JAVA程序设计语言中是采用按值调用

值传递和引用传递

值传递(pass by value)是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

引用传递(pass by reference)是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数,形参和实参总是指向同一个地址,形参指向哪里实参就会指向哪里。

java中的基本数据类型和引用数据类型

java中的基本数据类型:
  • 4种整数类型:byte、short、int、long
  • 2种浮点数类型:float、double
  • 1种字符类型:char
  • 1种布尔类型:boolean
java中的引用数据类型:
  • 接口
  • 数组

下面就对JAVA中传递参数是值传递还是引用传递展开讨论

下面先来看基本数据类型

代码语言:javascript
复制
public class Test {
    static void testInt(int a, int b)
    {
         a=10;
         b=20;
        System.out.println("交换后 "+"a:"+a+", b:"+b);
    }    
    public static void main(String[] args)
    {
        int a=1;
        int b=2;
        System.out.println("交换前 "+"a:"+a+", b:"+b);
        testInt(a,b);
        System.out.println("方法结束后"+"a:"+a+", b:"+b);
    } 

运行结果是这样的:

下面的头文字D的例子中:拓海 在栈中的实参名字,阿树 在栈中的形参名字 ,钥匙 指向堆中实例的地址,赛车 堆中的实例,比赛 程序中的方法(update,testInt)

java中基本数据类型在传递的时候,用的是值传递,就是拷贝和实参一模一样的值然后由形参进行操作,当方法结束后,形参的生命周期就会终止,实参的值并没有受到影响。

这里举个头文字D的例子,拓海有一辆AE86,过两天阿树有一场比赛,阿树想借拓海的这辆AE86,在比赛开始前拓海复制了一个一模一样的AE86给阿树,阿树又对这辆复制出来的AE86进行了改装,比赛结束后,阿树感觉比赛失利了,就开着车永久消失了。改装并没有影响到原来的AE86,这就是值传递,形参不会改变实参的值。

下面来看引用数据类型

代码语言:javascript
复制
//  类的编写
  class Car
  {
  public String name;
       public Car()
       {}
       public Car(String name)
       {
       this.name=name;
       }
  }

下面进行测试

代码语言:javascript
复制
public class Test
{
    public static void update1(Car car)
    {
      car.name="GTR";
      System.out.println("修改后的名字是:"+car.name);
    }
    //这个方法比上面的方法多了一条a=new Car()语句
    public static void update2(Car car)
    {
    car=new Car();
    car.name="GTR";
    System.out.println("修改后的名字是:"+car.name);
    }
    public static void main(String[] args)
    {
        Car a=new Car("AE86");
        Car b=new Car("AE86");
        System.out.println("调用update1前a的名字是:"+a.name);
        update1(a);
        System.out.println("调用update1后a的名字是:"+a.name);
        System.out.println("调用update2前b的名字是:"+b.name);
        update2(b);
        System.out.println("调用update2后b的名字是:"+b.name);

    }
}

运行结果是这样的:

看完上面的update1方法,觉得引用数据类型和基本数据类型不一样,引用数据类型传入方法后,方法调用结束后对象的属性发生了变化,认为这是引用传递,将对象a的地址送到了形参中,然后对形参改变实参就会改变。

但是update2马上就推翻了这个想法,将实参送入形参后,形参马上在堆中新建了一个对象,如果是引用传递,那么此时形参和实参都是指向这个对象的,然后程序又对形参的name属性进行了修改,那么此时实参也会被修改,看到的结果就应该和update1一样。但是结果却不是这样的,并没有修改数据,这就说明了将对象作为实参传入方法的形参,并不是引用传递。

那么java中引用类型数据到底是怎么回事那,下面把自己的查阅资料理解的写下来。作为后续回顾。
代码语言:javascript
复制
Car b = new Car(“AE86”);

执行这个语句首先会在栈中创建一个b变量,然后在堆中创建一个Car类的实例,然后b指向堆中的实例。

其实在java程序中,将对象传入形参中,也是值传递,基本数据类型值传递就是拷贝一个变量的副本;下面以update2()分析,引用数据类型就是将变量名(b)指向堆的地址复制一份,也就是说在栈中有一个变量名(car)也指向堆中b的实例。

现在执行 car =new car();就是形参car指向了堆中一个新的地址,而b还是指向原来的地址的,这样的话,car随便修改name属性,是影响不到b的。最后方法结束car被释放,堆中的新对象被GC回收。

在update1()中可以修改是因为形参和实参指向同一块内容,当形参修改name属性,那么堆中的对象就会被修改,update1()执行结束后,car释放,但堆中的实例还有变量指向,不会被回收,这时就修改了b的值。

还是用头文字D的例子来说明

引用传递:

还是有比赛,比赛(方法)前,拓海(栈中存的变量名,实参)将AE86(堆中类的实例)钥匙(地址)交给了阿树(形参),比赛途中阿树对AE86进行了改装,比赛后阿树消失了,但是钥匙给了拓海,那么此时的车是经过改装的。

Car=new Car();在例子中的体现:

比赛中,阿树感觉AE86不好开,旁边有一辆GTR,然后阿树用手上的这把钥匙捅开了GTR(new Car();),就开着GTR完成了比赛,AE86在路上找不到了(因为此时没有变量指向这辆AE86,会被GC回收),然后比赛完成后,阿树消失了,但钥匙给了拓海,此时的车是GTR。

JAVA中引用数据的传输

赛前,拓海将钥匙配了一个交给了阿树,阿树在比赛中对车进行了改装,比赛完之后阿树和钥匙一起消失了,那么拓海用钥匙开车,车是经过改装过的。

Car=new Car();在例子中的体现:

比赛中,阿树感觉AE86不好开,旁边有一辆GTR,然后阿树用配的的这把钥匙捅开了GTR(new Car();),这时候AE86是不会找不到的(因为此时拓海的钥匙还是指向这辆车的),阿树开着GTR完成了比赛,比赛后阿树和钥匙消失了,GTR也会消失(没有钥匙指向这辆车),此时的车还是AE86。

这两个是不同的:引用传递是真的将地址交给了形参,形参和实参始终指向堆中的一个类的实例;而java中引用类型的传递,则是将实参的地址复制一份交给了形参,这就符合值传递的概念,复制一个副本,只不过这里复制的是一个地址罢了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-11-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 国产程序员 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 值传递和引用传递
  • java中的基本数据类型和引用数据类型
    • java中的基本数据类型:
      • java中的引用数据类型:
        • 那么java中引用类型数据到底是怎么回事那,下面把自己的查阅资料理解的写下来。作为后续回顾。
          • 引用传递:
            • JAVA中引用数据的传输
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档