许多 Java 开发者在学习 Go 时,第一次看到 * 和 &,都会本能地紧张:
“Go 也要像 C 一样玩指针了吗?”
答案是:是指针,但和你想象的不一样。
本文将从 Java 开发者最熟悉的“引用”出发,帮你彻底搞清楚 Go 指针 vs Java 引用的本质差异。
一、Java 引用:你“用过”,但从没真正见过
在 Java 中:
User u = new User("Tom");
- u 是一个 引用
- 实际对象在 堆内存
- 引用本身不能运算
- 不能拿到真实内存地址
u = null; // 只能断开引用
Java 的原则:
开发者永远不直接接触内存地址
二、Go 指针:可见、可控、但很克制
在 Go 中:
type User struct {
Name string
}
u := User{Name: "Tom"}
p := &u
- u 是一个值
- p 是 u 的指针
- & 取地址
- * 解引用
fmt.Println(p) // 内存地址
fmt.Println(*p) // 实际值
Go 的态度:
允许你接触指针,但只在“安全范围内”
三、核心差异一览(先看结论)
|
维度 |
Java 引用 |
Go 指针 |
|
是否暴露地址 |
❌ |
✅ |
|
是否可运算 |
❌ |
❌(禁止指针运算) |
|
是否必需 |
隐式 |
显式 |
|
是否安全 |
高 |
高(受限) |
|
空值 |
null |
nil |
四、参数传递:Java 最容易误解的点
Java:永远是值传递
void change(User u) {
u = new User("Jack");
}
❗ 不会影响外部对象
但:
void changeName(User u) {
u.name = "Jack";
}
✔ 会影响对象内部状态
由于 拷贝的是“引用的值”
Go:值 or 指针,一眼就能看出来
func change(u User) {
u.Name = "Jack"
}
❌ 不会影响原值
func change(u *User) {
u.Name = "Jack"
}
✔ 会影响原值
Go 的好处:
是否修改原值,写在函数签名里
五、结构体方法:Java 类方法 vs Go 接收者
Java
class User {
String name;
void setName(String n) {
this.name = n;
}
}
Go(值接收者)
func (u User) SetName(n string) {
u.Name = n
}
❌ 不会修改原对象
Go(指针接收者)
func (u *User) SetName(n string) {
u.Name = n
}
✔ 会修改原对象
✔ 这是 Go 项目中最常见的写法
六、Java 开发者最关心的问题
❓ Go 会不会像 C 一样容易内存泄漏?
❌ 不会
- Go 有 GC
- 无指针算术
- 无手动释放内存
Go 指针 ≠ C 指针
❓ 那为什么 Go 还要指针?
三个核心缘由:
1️⃣ 避免大对象拷贝(性能)
2️⃣ 明确表达“我要修改你”
3️⃣ 实现接口和方法共享状态
七、什么时候该用 Go 指针?
✅ 推荐使用指针的场景
- 需要修改结构体内容
- 结构体较大
- 方法接收者
- 状态型对象(Service、Manager)
❌ 不推荐
- 基本类型(int、bool)
- 只读参数
- 临时值
八、一句话总结(送你一句爆款)
Java 用“看不见的引用”保护你,
Go 用“受限的指针”信任你。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
相关文章
暂无评论...

