Dan*_*her 15 java parameters terminology pass-by-reference
谁有权决定?
编辑:显然我没有成功地完善我的问题.
我不是在问Java的论证是如何传递的.我知道看起来像持有对象的变量实际上是一个包含对象引用的变量,并且该引用是按值传递的.这里有很多很好的解释(在链接的线程和其他线程中)和其他地方.
问题是关于术语传递的技术含义.(结束编辑)
我不确定这是否是SO的正确问题,如果没有道歉,但我不知道更好的地方.在这里的其他问题中已经说了很多,例如Java是"传递参考"还是"传递价值"?并通过引用或通过值传递?,但我没有找到该术语含义的权威答案.
我认为"通过引用传递"意味着"将引用(通常是指针)传递给对象",因此被调用者可以修改调用者看到的对象,而"按值传递"意味着复制对象,并让被调用者玩得开心(显而易见的问题:如果对象包含引用,深层复制或浅层).
唱FW变成了很多 的 地方 说: "按引用传递"的意思只是说,这里有一些说法,这意味着更多的,但仍然定义读
一种ParameterPassing模式,其中将实际参数的引用(或者如果你想在政治上不正确,指针)传递给形式参数; 当被调用者需要形式参数时,它取消引用指针以获取它.
我没有发现许多地方给出了更强的术语定义,在这个页面上,我发现"形式参数的左值设置为实际参数的左值".并且,如果我理解正确,这里使用相同的定义("形式参数仅作为实际参数的别名.")
事实上,我发现使用更强定义的唯一地方是反对这样一种观点,即在Java中,对象是通过引用传递的(这可能是由于我缺乏google-fu).
所以,如果我把事情弄清楚,那就是通过参考传递
class Thing { ... }
void byReference(Thing object){ ... }
Thing something;
byReference(something);
Run Code Online (Sandbox Code Playgroud)
根据第一个定义大致对应(在C中)
struct RawThing { ... };
typedef RawThing *Thing;
void byReference(Thing object){
// do something
}
// ...
struct RawThing whatever = blah();
Thing something = &whatever;
byReference(something); // pass whatever by reference
// we can change the value of what something (the reference to whatever) points to, but not
// where something points to
Run Code Online (Sandbox Code Playgroud)
从这个意义上讲,说Java通过引用传递对象就足够了.但根据第二个定义,传递参考意味着或多或少
struct RawThing { ... };
typedef RawThing *RawThingPtr;
typedef RawThingPtr *Thing;
void byReference(Thing object){
// do something
}
// ...
RawThing whatever = blah();
RawThingPtr thing_pointer = &whatever;
byReference(&thing_pointer); // pass whatever by reference
// now we can not only change the pointed-to (referred) value,
// but also where thing_pointer points to
Run Code Online (Sandbox Code Playgroud)
而且由于Java只允许你有对象的指针(限制你可以用它们做什么)但是没有指针指针,从这个意义上说,Java通过引用传递对象是完全错误的.
所以,
当然,不同的人目前对"传递参考"的含义有不同的定义.这就是为什么他们不同意某些东西是否通过引用传递.
但是,无论您使用的定义,你必须使用它始终跨语言.你不能说一种语言具有传值,并且在另一种语言中具有完全相同的语义,并且说它是传递参考.指出语言之间的类比是解决这一争议的最佳方式,因为虽然人们可能对特定语言中的传递模式有强烈的意见,但当你将相同的语义与其他语言进行对比时,它有时会带来反直觉的结果,迫使他们重新思考他们的定义.
如果一个人同意这个观点,那么人们也必须考虑大多数语言,包括Python,Ruby,OCaml,Scheme,Smalltalk,SML,Go,JavaScript,Objective-C等多种语言,仅作为传值.如果其中任何一个让你感到奇怪或违反直觉,我挑战你指出为什么你认为在Java中的任何语言中任何语言中的对象的语义不同.(我知道其中一些语言可能明确声称它们是传递引用;但它与它们所说的无关;必须根据实际行为对所有语言应用一致的定义.)
以Java为例:
class Thing { int x; }
void func(Thing object){ object.x = 42; object = null; }
Thing something = null;
something = new Thing();
func(something);
Run Code Online (Sandbox Code Playgroud)
在C中,它将等同于:
typedef struct { int x; } Thing;
void func(Thing *object){ object->x = 42; object = NULL; }
Thing *something = NULL;
something = malloc(sizeof Thing);
memset(something, 0, sizeof(something));
func(something);
// later:
free(something);
Run Code Online (Sandbox Code Playgroud)
我声称上述内容在语义上是等价的; 只有语法不同.唯一的语法差异是:
*表示指针类型; Java的引用(指向对象的指针)类型不需要显式*.->通过指针访问字段; Java只是使用.new为堆上的新对象动态分配内存; C用来malloc分配它,然后我们需要初始化内存.请注意,重要的是,
func(something),使用对象调用函数的语法都是相同的:不需要执行任何操作,例如获取地址或任何内容.object = null;函数内部都不会影响调用范围.因此在两种情况下语义都是相同的,所以如果你调用Java pass-by-reference,你也必须调用C pass-by-reference.
这两个C示例实际上都演示了pass-by-value,因为C没有pass-by-reference.只是你传递的值是一个指针.通过引用传递的语言如Perl:
sub set_to_one($)
{
$_[0] = 1; # set argument = 1
}
my $a = 0;
set_to_one($a); # equivalent to: $a = 1
Run Code Online (Sandbox Code Playgroud)
这里,变量$a实际上是通过引用传递的,因此子程序可以修改它.它没有修改一些$a通过间接指向的对象; 相反,它会改变$a自己.
在这方面,Java就像C一样,只是在Java对象中是"引用类型",所以你所拥有的(以及你所能传递的所有东西)都是指向它们的指针.像这样的东西:
void setToOne(Integer i)
{
i = 1; // set argument = 1
}
void foo()
{
Integer a = 0;
setToOne(a); // has no effect
}
Run Code Online (Sandbox Code Playgroud)
实际上不会改变a; 它只会重新分配i.
谁有权决定?没有人,也没有人.你自己决定; 作家决定他或她的书; 读者决定是否同意作者.
要理解这个术语,需要深入了解语言(并根据C代码解释它们而不是忽视这一点).参数传递样式是指编译器通常用于创建特定行为的机制.通常定义以下内容:
(术语注释:参数是子例程中定义的变量,参数是调用中使用的表达式.)
教科书通常也会按名称定义传递,但这种情况很少见,也不容易解释.通过需要也存在.
参数传递样式的重要性在于它的作用:在传递值时,对参数所做的任何更改都不会传递给参数; 在通过结果传递时,对参数所做的任何更改都会传递给最后的参数; 在通过引用传递时,对参数所做的任何更改都会在创建时传递给参数.
某些语言定义了多种传递样式,允许程序员分别为每个参数选择其首选样式.例如,在Pascal中,默认样式是按值传递,但程序员可以使用该var关键字指定按引用传递.其他一些语言指定一种传递方式.还有一些语言为不同类型指定不同的样式(例如,在C中,传递值是默认值,但数组是通过引用传递的).
现在,在Java中,从技术上讲,我们有一种带有pass-by-value的语言,对象变量的值是对象的引用.是否使Java传递引用的对象变量是一个品味问题.