“值语义”和“指针语义”是啥意思?

Posted

技术标签:

【中文标题】“值语义”和“指针语义”是啥意思?【英文标题】:What do ‘value semantics’ and ‘pointer semantics’ mean?“值语义”和“指针语义”是什么意思? 【发布时间】:2010-09-15 00:39:36 【问题描述】:

什么是“值语义”,什么是“隐式指针语义”?

【问题讨论】:

【参考方案1】:

Java 对 Object 类型使用隐式指针语义,对基元使用值语义。

值语义意味着您直接处理值并传递副本。 这里的重点是,当您拥有价值时,您可以相信它不会在您背后改变。

使用指针语义,您没有值,只有“地址”。 其他人可以改变那里的东西,你不知道。

C++ 中的指针语义:

void foo(Bar * b) ...
... b->bar() ...

你需要一个 * 来请求指针语义和 -> 调用指针上的方法。

Java 中的隐式指针语义:

void foo(Bar b) ...
... b.bar() ...

由于您无法选择使用值语义,因此不需要 * 也不需要区分 -> 和 .,因此是隐含的。

【讨论】:

【参考方案2】:

基本上,值语义意味着将一个值分配给另一个值会创建一个副本:

int x = 1;
int y = x;
x = 2; // y remains the same!

一种特殊情况是一个函数调用,它传递了一个参数:

void f(int x) 
    x = 5;


int a = 1;
f(a);
// a is still 1

这实际上对于 Java 和 C++ 是一样的。然而,Java 只知道一些基本类型,其中包括intdoublebooleanchar,以及以这种方式运行的枚举。所有其他类型都使用引用语义,这意味着将一个值分配给另一个实际上会重定向指针而不是复制底层值:

class Foo 
    int x;

    public Foo(int x)  this.x = x; 


Foo a = new Foo(42);
Foo b = a; // b and a share the same instance!
a.x = 32;
//b.x is now also changed.

但是有一些注意事项。例如,许多引用类型(StringInteger ...)实际上是不可变的。它们的值不能更改,对它们的任何赋值都会覆盖旧值。

此外,参数仍然按值传递。这意味着传递给函数的对象的值可以更改,但其引用不能:

void f(Foo foo) 
    foo.x = 42;


void g(Foo foo) 
    foo = new Foo(42);


Foo a = new Foo(23);
f(a);
// a.x is now 42!

Foo b = new Foo(1);
g(b);
// b remains unchanged!

【讨论】:

为什么是特殊情况? @morbidCode 什么特殊情况?论证通过?它实际上不是一个特殊情况,它的行为与赋值相同(它只是在语法上不是一个赋值)。 我不确定我明白了。您的意思是当您将 a 传递给 f(x) 时,会创建 a 的副本,然后为该副本分配值 5,因此当方法返回时,副本消失且原始 a 的值保持不变? 为了清楚起见,因为您和其他答案都说引用是按值传递的,而 g(Foo) 正在执行, b 实际上是否有两个指向它的指针,一个已经指向原始 b另一个在 g(foo) 中创建?同样适用于 ffoo( 和 a? 我终于明白了!谢谢。【参考方案3】:

Java 是按值传递的。 C++ 可以同时使用值和引用语义。

http://javadude.com/articles/passbyvalue.htm

【讨论】:

这种描述具有误导性,因为 Java 的隐藏指针(即使指针本身是按值传递的)。 @finnw :我同意,但是,Java 开发人员仍然应该这样理解,因为如果他们希望更改函数内部的指向数据,他们会惊讶于原来的外部“引用”是原封不动。所以这对他们了解他们的“参考”被复制很重要。 Bartosz: 很高兴看到人们传播我的文章 ;) finnw: “隐藏”是那里的关键词......我们正在谈论某人如何使用 Java 编程。幕后的实现机制不会' t 改变 Java 严格按值传递的事实——阅读 Java 语言规范以查看它的详细说明。 @ScottStanchfield:如果 Java 在技术上“按价值传递”,但并没有给程序员他们真正关心的价值,您会满意吗? Java 中唯一的值是原语和引用。 @EduardoLeón - 不确定你的意思。程序员将获得这些值,但他们在如何使用它们方面受到限制(这就是区别 - 通过值传递,他们无法修改值;他们只能读取原语或遵循指针......) 【参考方案4】:

Java 在变量访问上使用implicit pointer semantics(您不能直接编辑引用,它会自动(隐式)解析为访问时的对象)并且还在上使用Pass-by-Value semantics方法参数传递

阅读Pass-by-value semantics in Java applications:

在 Java 应用程序中,当一个对象 引用是方法的参数, 您正在传递一份 参考(按值传递),而不是 引用自己。请注意, 调用方法的对象引用和 副本指向同一个 目的。这是一个重要的 区别。一个 Java 应用程序 通过时没有什么不同 不同类型的参数,如 C++ 做。 Java 应用程序通过所有 参数值,从而使 所有参数的副本,无论 输入。

Short:Java 中的所有参数都是按值传递的。但这并不意味着对象被复制(就像 php4 中的默认值一样),而是对该对象的引用被复制。

你会在Pass-by-value semantics in Java applications看到所有的解释和深入的例子

【讨论】:

以上是关于“值语义”和“指针语义”是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章

Copy & Deepcope

python变量存储和深浅拷贝

c++的三种变量语义

c++的三种变量语义

我的OOP学习笔记值与引用语义类型

什么是值和引用语义及其区别