gpt4 book ai didi

java - 在C语言中更改变量的值时,是创建新的原语还是当前原语被突变?

转载 作者:太空狗 更新时间:2023-10-30 04:00:55 25 4
gpt4 key购买 nike

我知道“可变”和“不可变”是应该用来描述对象改变诸如Java和Objective C之类的面向对象语言中的值的能力的术语。但是,我想提出它,因为它与我的语言有关有关原始数据的问题。我知道,当我更改持有不可变对象的变量的值时,实际上是在创建一个新对象。但是,我想知道C中的基本数据的行为是否类似于不可变对象。我的意思是,当我更改保存原始数据的变量的值时,将创建新数据并由该变量引用。还是现有的原语实际上改变/修改了存储的数据值?

编辑#1:

问题#1:我想消除一些误解(无论是对我本人还是其他人),因为当我说“当我更改持有不可变对象的变量的值时,我实际上并不明确创建一个新对象。”当我这么说时,我并不是要将变量分配给现有对象。例如:

// Example 1: I did not mean this
-------------------------
String x = "Hello World";
String y = x;
-------------------------

// Example 2: What I meant is this
-------------------------
String x = "Hello World";
//This will print out "Hello World"
System.out.println(x);

x = "Goodbye World";
//This will print out "Goodbye World"
System.out.println(x);
-------------------------

当然,就像示例1中那样,将变量y分配给变量x,这就是你们提出的情况,只将变量y引用给x所引用的对象。当然,在这种情况下,没有新对象。只是同一对象“Hello World”被两个变量引用。

我的意思是,在示例2中,当x =“Goodbye World”时,变量x引用一个具有值“Goodbye World”的新String对象,而不是用x初始化的第一个String对象“Hello World”。字符串是Java中的不可变对象。更改String变量的值的唯一方法是让该变量引用现有对象 一个新的String对象。如果没有现有对象(“Goodbye World” String对象尚未在任何地方创建),则以上代码仅创建了一个新的String对象,并对其引用了x。我对吗?如果没有,请纠正我。

问题2:我想总结一下答案,尤其是 Ulfalizer 中的一个:

1)实际上,变量可以存在2种形式:

a)“内存地址”-对于C语言变量以及Java和Objective C有关原始类型数据的情况就是如此。例如:int x =1。这里的变量x是一个实际的内存地址本身,它的类型为integer,并用值1初始化。

b)“参考”-对于非原始类型数据(对象),Java中的大多数变量都是这种情况。例如:String x =“Hello World”。变量x只是指向“存在于某处的内存地址”的指针/引用,其内容为“Hello World”值。

2)C,Java和 objective-c 中的原始类型数据的变量充当“内存地址”。因此,当我这样做时:
-------------------------
int x = 10;
x = 2;
-------------------------

x变量的值(又名-内存地址)实际上从10更改为2。换句话说,可以修改/更改存储在“Memory Address”变量中的值。

3)在C语言中,如果变量以“*”(指针类型)声明,则它也可以充当引用。我将使用 Ulfalizer 的示例:int * ptr。 ptr是一个指针变量,可以指向另一个变量(即内存地址),例如:ptr =&x。如果x初始化为:int x = 10,则x是保存值为10的实际内存地址。因此在下面的代码中
-------------------------
int x;
int *ptr;
ptr = &x;
*ptr = 1;
-------------------------

我实际上可以通过ptr指针变量修改存储在x变量(又名-内存地址)中的值。

请确认我的解释是否正确/错误。谢谢。

最佳答案

理解C的工作方式的最佳方法是将其视为高级汇编语言。变量只是内存中的位置,将值分配给变量会将值存储到该位置。从高级语言的角度来看,这将是最纯粹形式的变异。

在C中,声明/定义如

int x;

告诉编译器为 int变量 x保留一些内存。 (在函数内部,内存将来自堆栈。在全局范围内,它将来自数据段。)

像这样的作业
x = 7;

只需生成代码即可将值7复制到该内存位置。同样,类似
x = y;

生成代码以将 int的存储位置中存储的 y值复制到 x的存储位置中。 (假设 y是另一个 int。)

同样的逻辑也适用于比 int更复杂的类型。

在Java中,变量是引用(反正是非原始类型),并且可以在不同时间引用不同的对象。为了获得类似于C中引用的内容,您必须显式定义一个指针变量(一个保存地址的变量),并在不同的时间将其指向不同对象的地址(为其分配地址)。

(为方便起见,我提供了以下示例。)
&运算符用于获取C语言中变量的地址,因此 &x将是 x的地址。 *运算符在应用于指针时会提供指向的对象。这是一个如何在不同时间使用指针来引用不同变量的示例:
int x;
int y;
/* Declares 'ptr' as a pointer, and says that it points to an int.
The pointed-to type is used by the compiler for type checking
and type conversions. */
int *ptr;

ptr = &x; // Store the address of 'x' in 'ptr'.
*ptr = 1; // Store 1 into the memory 'ptr' points to ('x').
ptr = &y; // Store the address of 'y' in 'ptr'.
*ptr = 2; // Store 2 into the memory 'ptr' points to ('y').

上面代码的最终结果是将 x设置为1并将 y设置为2。这当然是一个愚蠢的示例,但希望它能使您理解。

(顺便说一下,C99和更高版本支持 // -style注释。)

问题的答案

(注意:我的Java有点生锈,所以我必须做些阅读。希望细节应该正确。请随时纠正我。)

第1期

那作业
x = "Goodbye World";

会使 x引用值为“Goodbye world”的 String对象。确切地说,创建此 String对象的时间不应该有所不同,只要在将其分配给 x(或任何其他变量)之前创建该对象即可。

它可能是在执行分配之前或程序启动时创建的。通常,您将无法分辨出差异。

第2期

听起来您已经掌握了高级概念,并且您的C代码是正确的。

(尽管说“ ptr是一个指针”比说“ *ptr是一个指针”更正确。C中存在一些语法上的晦涩之处,这使得将 *放在声明(IMO)中的名称之后更加自然,但是您也可以在这种情况下编写类似于 int* ptr;的声明。只有在同一行中声明许多变量时,事情才会变得怪异。)

在讨论Java的实现方式时,引用可能必须比仅是底层对象的指针要先进一些。例如,JVM可能会在内存中移动对象(这将更改它们的地址)以减少内存碎片,但是引用仍必须保持有效。一种方法是在移动对象时“固定”指针,另一种方法是使引用成为指针表的索引。不管它在JVM实现中是如何完成的,指针至少都是正确的想法。

由于Java中的每个引用都有一个指针字段(在高层,完全忽略了实现的方式),并且由于原始类型不需要此字段,因此一种可能性是重用指针字段并将值存储在其中而不是原始类型。

例如,类似
x = 1;

可能将值1直接存储到参考 x的指针字段中。这样的技术很普遍。

附带说明一下, union可以在C语言中用于将两种不同的类型(例如 int和指针)存储在内存中的同一位置,以便它们重叠。当然,分配给其中一种类型也会改变另一种类型的值。

关于java - 在C语言中更改变量的值时,是创建新的原语还是当前原语被突变?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29247824/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com