Java可以按引用调用吗?

学习Java中,最大的问题并不是语言本身,而是一些经验和固有的认知,有些基本的知识,已经根深蒂固,但是如果换个编程语言,思维的惯性可能是有害的。

例如,关于按值调用(call by value)和按引用调用(call by reference),这两种方式在C++中已经是司空见惯的老生常谈问题,对于这个现象的描述,swap函数的出场率也是非常高的。

那么,在Java中又是如何?首先,在Java中,对于基本的数字类型,例如int或者Boolean等,传递的都是值的一个副本,下列方法/函数:

void addOne(int x)
{
    x+=1;
}

调用前后,作为实参的int变量,其值并不会发生改变,更夸张的是,你甚至可以传递一个int的字面量,而字面量是不能够作为左值的。有一点点C/C++基础的都知道,函数调用的时候,实际上是把参数的副本压入了函数的栈中,当然这个基础的知识也没必要浪费太多的篇幅阐述了。

接下来回到了问题的关键,我们知道,方法在调用的时候,其参数还有可能是对象引用,Java中的情况又是如何呢?我们先写一个类:

class Myc
{
    int x;
    String name;
    public Myc(String name,int x)
    {
        this.name=name;
        this.x=x;
    }
    public void setX(int x)
    {
        this.x=x;
    }
    public int getX()
    {
        return this.x;
    }

    @Override
    public String toString()
    {
        return name+":"+this.x;
    }
}

然后再定义一个修改其参数的函数,以及在主函数中的测试代码:

    public static void main(String[] args) 
    {
        Myc x = new Myc("first object",10);
        System.out.println(x);
        objAddOne(x);
        System.out.println(x);

    }

    public static void objAddOne(Myc c)
    {
        c.setX(c.getX()+1);
    }

不出意料的,这个程序的输出结果是:

first object:10
first object:11

看样子,通过方法的调用,我们修改了所传入的对象,这么看来,行为和按引用调用很像嘛,但是这个就真的是按引用调用吗?

我们知道,按引用调用的一个显著特征是你可以实现对象引用的交换,以C语言代码为例:

void swap(int* x,int* y)
{
    int t=*x;
    *x=*y;
    *y=t;
}

刚好可以在Java中测试一下类似的方法:

public static void main(String[] args)
    {
        Myc x = new Myc("first object",10);
        Myc y=new Myc("second object",20);
        swapObject(x,y);
        System.out.println(x);
        System.out.println(y);
    }
    public static void swapObject(Myc a,Myc b)
    {
        Myc temp=a;
        a=b;
        b=temp;
    }

如果是按引用传递,那么它们应该能够实现交换,实际输出结果为:

public static void main(String[] args)
    {
        Myc x = new Myc("first object",10);
        Myc y=new Myc("second object",20);
        swapObject(x,y);
        System.out.println(x);
        System.out.println(y);
    }
    public static void swapObject(Myc a,Myc b)
    {
        Myc temp=a;
        a=b;
        b=temp;
    }

就像什么都没发生一样。那么问题出在哪里呢?实际上,swapObject函数的参数a和b也是两个对象的副本,这个方法交换的,其实是副本,可以在swapObject函数中展开验证一下:

    public static void swapObject(Myc a,Myc b)
    {
        Myc temp=a;
        a=b;
        b=temp;
        System.out.println("In swapObject:");
        System.out.println(a);
        System.out.println(b);
    }

再次运行的结果是:

In swapObject:
second object:20
first object:10
first object:10
second object:20

可以看到,在方法中,确实两个对象产生了交换,但是退出方法以后,所有的努力都化为乌有,这和最开始的那个addOne是一样的效果。

所以根本原因在哪里呢?在Java中,对象引用也是按值传递的。

总结Java中对方法参数的行为:

1. 方法不会修改基本数据类型的参数;

2. 方法可以修改对象参数的状态(例如通过objAddOne实现了对状态x的修改)

3. 方法不能让一个对象参数引用到一个新对象上。

4. 修改对象的状态和修改引用是两回事。

最后的最后,问题的答案是什么?Java的方法并不使用按引用调用。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值