Java到底是值传递还是引用传递

Java到底是值传递还是引用传递

先说结论,Java中只有值传递,没有引用传递。值传递和引用传递的根本区别是有没有变量的拷贝,或者说有没有变量的副本

啥叫值?值就是内存中真实存在的数据,就像碗里装的饭,盆里装的水一样。

啥叫引用?引用就是装值这块内存区域的地址,在碗上贴个标签写上张三,下次我要找张三的碗我直接看标签就行了,这个标签就是引用。(假设所有的碗颜色形状大小都一样)

啥叫指针?指针就是这块内存我不装数据了,装的是另外一块内存的地址,我在一个小碗里面装个标签,上面写着张三,通过这个小碗我找到了张三的大碗,你没看错,通过碗找碗,小碗找大碗,通过一小块内存找到一大块内存,就是指针。

啥叫值传递?把这块内存中的数据拷贝到另外一块内存里面去,把张三碗里面的饭原封不动的复制到另外一个碗里面去,另外一个碗拿着这碗饭开始消费数据,消费这碗饭里面的数据对张三碗里面的饭有影响吗?并没有,这就叫值传递。

啥叫引用传递?内存地址的传递叫作用传递,操作的都是同一块内存区域,我要吃饭(消费数据),把张三的碗上的标签给了我,那我自然找到张三的碗开始吃,这就叫引用传递。

啥叫指针传递?指针传递本质也是值传递!有个有张三标签的小碗,这个是个指针对不,现在把这个小碗里面的标签原封不动的复制到另外一个小碗里面去,那么两个小碗都能通过张三这个标签找到张三的碗,这是同一个碗嘛,这就叫指针传递。

什么是值传递

话不多说,直接看代码

public class PassByValue {
    public static void main(String[] args) {
        int a = 0;
        adder(a);
        System.out.println("main方法中的a为:" + a);
    }

    public static void adder(int b) {
        b = 1;
        System.out.println("方法adder中的b为:" + b);
    }
}

输出为

方法adder中的b为:1
main方法中的a为:0

adder中的b是main中a的一个拷贝,所以任何对b的操作不会影响到a,a该是多少还是多少,这就是值传递。值传递传递的是原始变量的一个拷贝,这个就是关键!

来看看C版本的,一模一样的有没有发现。

void f( int  p){
    printf("\n%x",&p);
    printf("\n%x",p);
    p=0xff;
}
void main()
{
    int a=0x10;
    printf("\n%x",&a);
    printf("\n%x\n",a);
    f(a);
    printf("\n%x\n",a);
}

执行如下图

image

什么是引用传递

引用传递,那就是传递这根儿引用,千万别和Java里面的引用类型混淆,这里说的是引用,不是引用类型引用类型四个字儿呢,这俩字儿叫引用,哪这根儿引用到底是个啥? 说白了就是内存地址引用传递操作的都是同一块内存

内存地址

引用就是****内存地址

image

内存地址如上图所示,你可以把它想象成一条无限长的纸条,纸条上面的每个格子是一个内存单位,就是实际放东西的地方,纸条下面的格子就是这块内存的内存地址,就是一个位置,通过这个位置可以拿到这块内存中实际存放的东西,通常我们说的寻址,就是通过这么个地址找到这块内存!

引用传递

上面说了,引用就是内存地址,那么引用传递也就是这块内存地址的传递,怎么个传递法?以C语言为例(Java中没有引用传递,所以要类比C中的引用传递才能帮助理解)

void f( int & p){
    printf("\n%x",&p);
    printf("\n%x",p);
    p=0xff;
}
void main()
{
    int a=0x10;
    printf("\n%x",&a);
    printf("\n%x\n",a);
    f(a);
    printf("\n%x\n",a);
}

f的入参& p就表示一个引用(内存地址),p表示这块内存地址中实际装着的值,看下运行结果

image

不出意外,main中的a也被改掉了,main中的a和f中的p实际上表示的是同一块内存!当然改了一个另外一个也被影响了!

整个过程都在操作一块内存,没有内存被拷贝!这才是正儿八经的引用传递

Java中引用类型的值传递和正儿八经的引用传递有啥区别?

很多人都在这里混淆,Java中引用类型的传递不就是引用传递?人家叫引用类型的值传递,你简称引用传递,后面四个字被你吃了??引用类型实际上都是指针,你也可以说成是指针传递

Java中的指针

先看看Java中最具误导性的例子

public class PassByValueForReference {

    public static void main(String[] args) {
        Person p1 = new Person("张三");
        System.out.println("改名之前的person:" + p1);
        nameChanger(p1);
        System.out.println("改名之后的person:" + p1);
    }

    static void nameChanger(Person p){
        p.name = "李四";
    }

    private static class Person{
        String name;
        public Person(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return this.name;
        }
    }
}

输出结果如下:

改名之前的person:张三
改名之后的person:李四

张三的引用p1被传递到nameChanger方法里面,然后nameChanger拿到张三的引用p执行改名操作后,main里面的张三变成了李四,这不就是引用传递!?

当然不是!首先p1不是个引用,p1是个指针!什么指针?指向张三的指针!Java中的引用类型是栈上的一小块内存(通常为4字节)指向堆上的一大块内存,这小块内存里面放的不是真正的数据,而是存的堆上大块内存的内存地址!这不就是指针么。

其次,nameChanger拿到的并不是张三的引用p,而是张三的指针p1的拷贝,小本本记下来,又出现了拷贝这个词了,既然是张三的指针那当然指向张三了,既然是张三的指针那当然也能指向别的Person,比如李四、王麻子

总而言之,言而总之,Person p1 = new Person(“张三”);,static void nameChanger(Person p)中的p1和p都是指针,不是真正的引用! 一图胜千言

image

Java中的指针传递

把上面的例子稍微改一下,就改动了一行代码

public class PassByValueForReference {

    public static void main(String[] args) {
        Person p1 = new Person("张三");
        System.out.println("改名之前的person:" + p1);
        nameChanger(p1);
        System.out.println("改名之后的person:" + p1);
    }

    static void nameChanger(Person p){
        //p.name = "李四";
        p = new Person("李四");
    }

    private static class Person{
        String name;
        public Person(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return this.name;
        }
    }
}

输出结果

改名之前的person:张三
改名之后的person:张三

看到没,nameChanger并没影响到main,按理说引用传递操作的都是同一块内存,所以main中的也应该是李四,但实际证明并不是,这也从侧面说明Java中没有引用传递!

上面的操作如下图所示:

所以最后明白了么?Java中没有引用,全都是指针!引用类型就是指针!Java中著名的异常都叫空指针异常,所以你明白了吧。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

代码狂魔v

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值