java:值传递,引用传递,为什么JAVA只有值传递(含图解)

前言
JAVA对于对象类型的参数传递,主流解释是:“JAVA传递对象类型的时候,传递的不是对象本身,而是对象的地址”。这句话容易让人误解为这是引用传递,确实这种传递方式表现得类似于引用传递,但实际上JAVA仍然是值传递。

0.太长不看

核心区别:
值传递:传递引用的副本(将对象的地址复制到新的一块内存中传递
引用传递:传递引用本身(直接传递对象的地址


1.图片解释

看下面的例子:
我有一个类Food,三个对象Food 鸡蛋、Food 苹果、Food 西瓜,一个引用Food 引用,一个方法 void eat(Food food)
        对于对象的“引用传递”

        对于对象的“值传递”

接下来,我想在eat中修改原来的“Food 引用”,让其引用苹果,那么就发生区别了。比如要将“Food 引用”改成引用“Food 苹果”,那么就回出现下面的区别:
        对于对象的“引用传递”
 

        对于对象的“值传递”


看到区别了吗,引用传递可以在eat()内部修改“Food 引用”本身,让其转而引用“Food 苹果”;值传递,在eat()内部只能修改“Food 引用的副本”,不能修改“Food 引用”本身。

2.代码示例:
 

class Food {
    String name;
    
    Food(String name) {
        this.name = name;
    }
    
    void eat() {
        System.out.println("Eating " + name);
    }
}

public class FoodExample {
    public static void main(String[] args) {
        Food egg = new Food("Egg");
        Food apple = new Food("Apple");
        
        System.out.println("=== 初始状态 ===");
        System.out.println("main方法中: egg指向=" + egg.name);
        System.out.println("main方法中: apple指向=" + apple.name);
        
        System.out.println("\n=== 调用eat方法,传入egg ===");
        eat(egg, apple);
        
        System.out.println("\n=== eat方法调用后 ===");
        System.out.println("main方法中: egg指向=" + egg.name); // 仍然是Egg!
        System.out.println("main方法中: apple指向=" + apple.name);
    }
    
    // 尝试在方法中修改引用指向
    static void eat(Food food, Food newFood) {
        System.out.println("eat方法开始时: food指向=" + food.name);
        
        // 尝试修改引用指向apple
        food = newFood;  // 这里只修改了副本引用!
        
        System.out.println("eat方法修改后: food指向=" + food.name);
        food.eat();  // 这里吃的是Apple,但只在方法内有效
    }
}

输出结果:
 

=== 初始状态 ===
main方法中: egg指向=Egg
main方法中: apple指向=Apple
=== 调用eat方法,传入egg ===
eat方法开始时: food指向=Egg
eat方法修改后: food指向=Apple Eating Apple
=== eat方法调用后 ===
main方法中: egg指向=Egg
main方法中: apple指向=Apple

3. 内存模型图解

调用 eat(egg, apple) 时的内存状态:

text

栈内存:
main方法栈帧:
egg   ─────→ [Food对象] name="Egg"
apple ─────→ [Food对象] name="Apple"

eat方法栈帧:
food (egg的副本) ───→ [Food对象] name="Egg"  
newFood (apple的副本) → [Food对象] name="Apple"

执行 food = newFood 后:

text

main方法栈帧:                    (未变化)
egg   ─────→ [Food对象] name="Egg"
apple ─────→ [Food对象] name="Apple"

eat方法栈帧:
food (现在指向apple) ──────────→ [Food对象] name="Apple"  
newFood ──────────────────────┘

4. 关键区别总结

特征Java实际(值传递引用)真正的引用传递
传递内容引用的副本引用本身
修改引用指向只影响方法内的副本影响原始引用
修改对象内容会影响原始对象会影响原始对象
比喻给钥匙复印件给钥匙原件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值