java与python函数参数传递类比

Python3.8

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

Java 里“对象变量”到底是什么?
以及
函数里改的到底是“对象本身”还是“参数这个局部变量”

我用最接地气的方式给你捋。


1. Java 里的“对象变量”是什么意思

在 Java 里,变量大致分两类:

第一类:基本类型变量

比如:

int a = 10;
double b = 3.14;
char c = 'A';
boolean flag = true;

这些变量里放的就是“值本身”。


第二类:引用类型变量(你刚说的“对象变量”基本就是这个意思)

比如:

String s = "hello";
User u = new User();
List<Integer> list = new ArrayList<>();

这里的:

  • s

  • u

  • list

都不是直接装“对象本体”,
而是装着一个引用,你可以粗略理解成“对象的地址/门牌号/指向对象的箭头”。

所以“对象变量”其实更准确地说是:

引用类型的变量
也就是:这个变量里存的不是对象内容本身,而是对象的引用。


2. Java 为什么说“值传递,但对象变量里存的是引用”

这个说法第一次看确实很绕。

比如:

public static void test(int x) {
x = 20;
}

调用:

int a = 10;
test(a);
System.out.println(a); // 10

这是最普通的值传递:

  • a 的值是 10

  • 调用函数时,把 10 复制一份给 x

  • 你改 x,不会影响 a


再看对象:

public static void test(User u) {
u.age = 20;
}

调用:

User user = new User();
user.age = 10;
test(user);
System.out.println(user.age); // 20

这里很多人就会以为“Java 是引用传递”。

其实不是。

真正发生的是:

  • user 这个变量里存的是一个“引用”

  • 调用 test(user) 时,传过去的是这个引用的副本

  • 虽然是副本,但它和原来的 user 仍然指向同一个对象

  • 所以 u.age = 20 本质上是在改那个共同指向的对象

所以 Java 依然是值传递,只不过传递的这个值,恰好是“引用”。


3. 你说的这句,理解得差不多了

你问:

指的是这个函数形参是对象吗,而不是基本数据类型?

对,基本可以这么理解。

更准确点说:

  • 如果形参是 intdouble 这种,传的是基本类型值

  • 如果形参是 UserStringList 这种,传的是引用值

比如:

public static void f1(int x) {}
public static void f2(User u) {}
public static void f3(List<Integer> list) {}

这里:

  • x 是基本类型参数

  • ulist 是引用类型参数


4. 判断会不会影响实参,要看“改的是什么”

这是最重要的。

你说:

然后看在函数里面的修改会不会影响到真实的实参对象?

对,但你要分成两种“修改”。


情况 A:修改对象内部状态

例如:

class User {
int age;
}
public static void change(User u) {
u.age = 99;
}

调用:

User user = new User();
user.age = 18;
change(user);
System.out.println(user.age); // 99

为什么会影响?

因为:

  • uuser 指向的是同一个 User 对象

  • u.age = 99 是在修改这个对象本身

所以外面能看到变化。


情况 B:让形参指向一个新对象

例如:

public static void change(User u) {
u = new User();
u.age = 99;
}

调用:

User user = new User();
user.age = 18;
change(user);
System.out.println(user.age); // 18

为什么这次外面没变?

因为:

  • 一开始 uuser 指向同一个对象

  • u = new User() 之后,u 改去指向新对象了

  • 外面的 user 还指向原来那个对象

所以外面不受影响。


5. 一句话总结 Java

你可以先记这个:

Java 参数永远是值传递。

如果传的是基本类型,复制的是值。
如果传的是对象类型,复制的是引用。
改对象内容会影响外面,改形参自己的指向不会影响外面。


6. Python 和这个非常像

你说:

Python你说的是基本数据类型的修改是不会影响到实参的,但是如果传的是可变类型的对象就会原地修改实参对象?

对,这个理解基本是对的。

但我帮你再修正得更精确一点。


Python 里,不要硬分“基本数据类型”

Python 更常见的分法是:

  • 不可变类型intfloatstrtuplebool

  • 可变类型listdictset


不可变类型:函数里改,通常不影响外面

例如:

def f(x):
x = x + 1

a = 10
f(a)
print(a) # 10

为什么?

因为整数不可变,x = x + 1 不是修改原来的 10
而是让 x 重新绑定到新对象 11

外面的 a 还是原来的 10


可变类型:如果原地改,会影响外面

例如:

def f(lst):
lst.append(4)

a = [1, 2, 3]
f(a)
print(a) # [1, 2, 3, 4]

为什么会影响?

因为:

  • lsta 指向同一个列表对象

  • append 是原地修改列表内容

所以外面能看到变化。


但如果只是重新绑定,也不会影响外面

例如:

def f(lst):
lst = [100, 200]

a = [1, 2, 3]
f(a)
print(a) # [1, 2, 3]

因为这里不是改原来的列表,
而是让 lst 这个局部变量指向了一个新列表。

和 Java 的这个现象非常像。


7. 你现在可以这样对比 Java 和 Python

Java

  • 基本类型:改形参,不影响实参

  • 引用类型:

    • 改对象内容,影响实参对象

    • 改形参指向,不影响实参

Python

  • 不可变对象:通常不会影响外面

  • 可变对象:

    • 原地修改对象内容,会影响外面

    • 重新绑定参数,不影响外面


8. 给你一个并排对比,你就更清楚了

Java

class User {
int age;
}

public class Main {
public static void changeAge(User u) {
u.age = 30;
}

public static void changeRef(User u) {
u = new User();
u.age = 50;
}

public static void main(String[] args) {
User user = new User();
user.age = 18;

changeAge(user);
System.out.println(user.age); // 30

changeRef(user);
System.out.println(user.age); // 30
}
}


Python

def change_content(lst):
lst.append(4)

def change_ref(lst):
lst = [100, 200]

a = [1, 2, 3]

change_content(a)
print(a) # [1, 2, 3, 4]

change_ref(a)
print(a) # [1, 2, 3, 4]


9. 最后我帮你把你的这句话改成标准理解

你原来的理解可以整理成这样:

Java

Java 是值传递。
如果参数是基本类型,传的是值本身。
如果参数是对象类型,传的是对象引用的副本。
所以函数里修改对象内容,可能影响实参对应的对象;
但让形参重新指向新对象,不会影响实参。

Python

Python 函数参数传递的是对象引用。
对于不可变对象,操作通常会产生新对象,所以不会影响外面的变量;
对于可变对象,如果在函数里原地修改对象内容,就会影响外面的对象;
如果只是让形参重新绑定到新对象,则不会影响外面的变量。

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值