Java Ruby是按值传递还是按引用传递?

Java Ruby是按值传递还是按引用传递?,java,ruby,oop,pass-by-reference,pass-by-value,Java,Ruby,Oop,Pass By Reference,Pass By Value,我基本上是一名java开发人员。我在ruby工作了大约一年。与java不同,Ruby是一种纯粹的面向对象编程语言。这是一个疑问。它是按值传递还是按引用传递?Java作为传递值工作:“当传递原语时,我看到值被复制并传递给方法。但是对于对象,引用被复制并传递给方法。引用包含对象在堆中的位置。在方法调用期间,只传递对象的位置。因此不会创建重复的对象。同一对象被修改。” 但是,当我尝试下面的ruby代码片段时,我得到了与Java中相同的结果:“在方法调用期间,数字像原语一样工作(如Java中),而数组像

我基本上是一名java开发人员。我在ruby工作了大约一年。与java不同,Ruby是一种纯粹的面向对象编程语言。这是一个疑问。它是按值传递还是按引用传递?Java作为传递值工作:“当传递原语时,我看到值被复制并传递给方法。但是对于对象,引用被复制并传递给方法。引用包含对象在堆中的位置。在方法调用期间,只传递对象的位置。因此不会创建重复的对象。同一对象被修改。”

但是,当我尝试下面的ruby代码片段时,我得到了与Java中相同的结果:“在方法调用期间,数字像原语一样工作(如Java中),而数组像Java中一样作为完美引用工作”。现在,我感到困惑。如果ruby中的所有内容都是对象,那么为什么数字对象在方法调用期间重复

class A
  def meth1(a)
    a = a+5
    puts "a inside meth1---#{a}"
  end

  def meth2(array)
    array.pop
    puts "array inside meth2---#{array}"
  end
end


obj1 = A.new
aa=5
obj1.meth1(aa)
puts "aa-----#{aa}"

arr = [3,4,5]
obj1.meth2(arr)
puts "arr---#{arr}"
结果:

a内部方法1-10

aa---5

数组2---34


arr---34

见下文,
对象id
将回答您的所有问题:

class A
 def meth1(a)
  p a.object_id #=> 11
  a = a+5 # you passed a reference to the object `5`,but by `+` you created a new object `10`.
  p a.object_id #=> 21
 end

 def meth2(array)
  p array.object_id #=> 6919920
  array.pop
  p array.object_id #=> 6919920
 end
end


obj1 = A.new
aa=5
obj1.meth1(aa)
p aa.object_id #=> 11

arr = [3,4,5]
obj1.meth2(arr)
p arr.object_id #=> 6919920

因此,在您的代码中,
对象引用确实是通过值传递的。注意
+
创建一个新对象,因此引用是在本地对其更改的方法进行的
10

在这两种情况下都是通过值传递的,就像Java一样。区别在于测试中的两个项目都是对象,而在Java中则是一个一个是基元,另一个是对象。但某个对象是基元还是对象与传递值与传递引用无关。传递值与传递引用与被调用方法对传递给它的调用上下文中的变量所做的操作有关

让我们忽略这两种语言和对象,看看“按值传递”和“按引用传递”的实际含义。我将使用模糊的B/Java/C/C++/C#/D语法中的伪代码:

Function Foo(arg) {
  arg = 6
}

declare variable a
a = 5
Foo(a)
output a
如果
a
通过值传递,则输出为5。如果
a
通过引用传递(变量
a
的引用被赋予
Foo
),则输出为6,因为
Foo
通过变量引用处理
a

请注意,您的两个测试之间有很大的差异

在第一次测试中,您将为
a
分配一个全新的值:

a = a + 5
您没有修改传递到方法中的
a
的版本,而是使用该值为
a
分配一个新值

在第二个测试中,您只需修改
数组

array.pop
不是,例如:

array = ...put something entirely new in `array`...

在您的测试中,因为您只是修改对象引用指向的对象,而不是更改引用,所以您当然看到了这种修改。但是如果您实际将一个新数组分配给
array
,那么这种更改在调用上下文中并不明显。

Ruby作为Java,是按值传递的…带有一个catch:the“value”传递的是指针引用(如果是对象),因此如果在方法内部对对象值进行任何修改,它将位于调用上下文中的对象所在的同一对象上

现在,在您的示例中,您需要知道的是只有一个值的“立即”对象——在本例中,引用不是指针,而是对象本身(它仍然是一个对象,带有方法等,因此这不像Java中的原语)

在您的示例中,您实际上是在将新对象重新指定给“a”指针,在任何情况下,它都不会在任何地方反映出来,如下所示:

my_name = "John"
my_name = "Robert"
实际上是为引用分配一个新指针。由于在Ruby中无法更改FixNum的值,因此这种情况不可行


数组的情况可能是您所期望的:您有一个对象,您对对象状态进行修改,然后将修改后的状态恢复到原来的状态。

Ruby使用按值传递,或者更准确地说,是按值传递的一种特殊情况,其中传递的值始终是指针。这种特殊情况有时也称为按共享调用、按对象调用共享或按对象调用

这与Java(用于对象)、C#(默认情况下用于引用类型)、Smalltalk、Python、ECMAScript/JavaScript以及几乎所有创建的面向对象语言所使用的约定相同

注意:在所有现有的Ruby实现中,
Symbol
s、
Fixnum
s和
Float
s实际上是通过值直接传递的,而不是通过中间指针。然而,由于这三者是不可变的,在这种情况下,传递值和按对象调用共享之间没有明显的行为差异,因此您可以通过简单地将所有内容视为按对象调用共享来大大简化您的心智模型。只需将这三种特殊情况解释为您不需要担心的内部编译器优化

下面是一个简单的示例,您可以运行它来确定Ruby(或任何其他语言,在翻译后)的参数传递约定:


令人惊叹的!!!你是个天才。感谢您的详细回复:)
在所有现有的Ruby实现中,符号、Fixnums和float实际上是直接通过值传递的,而不是通过中间指针。
我非常喜欢,我想,应该包括。但你做到了,看起来不错但是我认为你也应该在你的列表中包括
true
nil
false
。。。。说“foo.relpace('some text')”谢谢你的回答:)“测试中的两个项目都是对象”实际上它们都是引用。“对象”不是Java或Java中的值Ruby@newacct:否,测试中的两个项目都是对象(数字对象和数组对象)。是的,当这些被传递到一个函数中时,传递的是对该对象的引用(而不是对象本身),这在abov中是非常清楚的
def is_ruby_pass_by_value?(foo)
  foo.replace('More precisely, it is call-by-object-sharing!')
  foo = 'No, Ruby is pass-by-reference.'
  return nil
end

bar = 'Yes, of course, Ruby *is* pass-by-value!'

is_ruby_pass_by_value?(bar)

p bar
# 'More precisely, it is call-by-object-sharing!'