Java是“通过引用传递”还是“传递价值”?

我一直认为Java是传递引用的

但是,我看过一些博客文章(例如,这个博客)声称它不是。

我不认为我理解他们所做的区别。

解释是什么?


守着星空守着你
浏览 651回答 6
6回答

冉冉说

Java始终是按值传递的。不幸的是,当我们传递一个对象的值时,我们将引用传递给它。这对初学者来说很困惑。它是这样的:public static void main(String[] args) {     Dog aDog = new Dog("Max");     Dog oldDog = aDog;     // we pass the object to foo     foo(aDog);     // aDog variable is still pointing to the "Max" dog when foo(...) returns     aDog.getName().equals("Max"); // true     aDog.getName().equals("Fifi"); // false     aDog == oldDog; // true}public static void foo(Dog d) {     d.getName().equals("Max"); // true     // change d inside of foo() to point to a new Dog instance "Fifi"     d = new Dog("Fifi");     d.getName().equals("Fifi"); // true}在上面的例子中aDog.getName()仍将返回"Max"。值aDog内main未在功能改变foo与Dog "Fifi"作为对象基准由值来传递。如果它是通过引用传递的,则aDog.getName()in main将"Fifi"在调用之后返回foo。同样:public static void main(String[] args) {     Dog aDog = new Dog("Max");     Dog oldDog = aDog;     foo(aDog);     // when foo(...) returns, the name of the dog has been changed to "Fifi"     aDog.getName().equals("Fifi"); // true     // but it is still the same dog:     aDog == oldDog; // true}public static void foo(Dog d) {     d.getName().equals("Max"); // true     // this changes the name of d to be "Fifi"     d.setName("Fifi");}在上面的例子中,Fifi是调用后的狗的名字,foo(aDog)因为对象的名字是在里面设置的foo(...)。任何操作foo执行上d是这样的,对于所有的实际目的,它们被执行的aDog,但它是不是可以改变变量的值aDog本身。

缥缈止盈

我刚刚注意到你引用了我的文章。Java规范说Java中的所有内容都是按值传递的。在Java中没有“pass-by-reference”这样的东西。理解这一点的关键是类似的东西Dog myDog;是不是狗; 它实际上是指向狗的指针。这意味着,就在你拥有的时候Dog myDog = new Dog("Rover");foo(myDog);你实际上是将创建的对象的地址传递Dog给foo方法。(我说的主要是因为Java指针不是直接地址,但最容易想到它们)假设Dog对象驻留在内存地址42处。这意味着我们将42传递给该方法。如果方法被定义为public void foo(Dog someDog) {     someDog.setName("Max");     // AAA     someDog = new Dog("Fifi");  // BBB     someDog.setName("Rowlf");   // CCC}让我们来看看发生了什么。参数someDog设置为值42在线“AAA”someDog跟随Dog它指向(Dog地址42处的对象)要求Dog(地址为42的那个)将他的名字改为Max在线“BBB”Dog创建了一个新的。让我们说他在地址74我们将参数分配someDog给74在线“CCC”someDog跟随Dog它指向(Dog地址74处的对象)要求Dog(地址为74的那个)将他的名字改为Rowlf然后,我们回来了现在让我们考虑一下方法之外会发生什么:没有myDog改变?关键是。记住这myDog是一个指针,而不是一个实际的Dog,答案是否定的。myDog仍然有42的价值; 它仍然指向原始Dog(但请注意,由于行“AAA”,它的名称现在是“Max” - 仍然是相同的狗;它myDog的值没有改变。)按照地址并改变最后的内容是完全有效的; 但是,这不会改变变量。Java的工作方式与C完全相同。您可以分配指针,将指针传递给方法,按照方法中的指针操作并更改指向的数据。但是,您无法更改指针指向的位置。在C ++,Ada,Pascal和其他支持pass-by-reference的语言中,您实际上可以更改传递的变量。如果Java具有pass-by-reference语义,那么foo我们在上面定义的方法会在BBB上myDog分配的位置发生变化someDog。将引用参数视为传入的变量的别名。当分配该别名时,传入的变量也是如此。

神不在的星期二

这将为您提供一些有关Java如何工作的见解,以至于在您下次讨论Java通过引用传递或通过值传递时,您只需微笑:-)第一步请从脑海中删除以'p'“_ _ _ _ _ _ _”开头的单词,特别是如果您来自其他编程语言。Java和'p'不能写在同一本书,论坛,甚至txt中。第二步记住,当你将一个Object传递给一个方法时,你传递的是Object引用,而不是Object本身。学生:师父,这是否意味着Java是传递参考?师父:蚱蜢,没有。现在想想Object的引用/变量是什么/是什么:变量保存位,告诉JVM如何到达内存中引用的Object(Heap)。将参数传递给方法时,您不会传递引用变量,而是传递引用变量中的位副本。像这样:3bad086a。3bad086a代表了一种获取传递对象的方法。所以你只是传递3bad086a,它是参考的价值。您传递的是引用的值而不是引用本身(而不是对象)。该值实际上是COPIED并赋予方法。在下面(请不要尝试编译/执行此...):1. Person person;2. person = new Person("Tom");3. changeName(person);4.5. //I didn't use Person person below as an argument to be nice6.  static void changeName(Person anotherReferenceToTheSamePersonObject) {7.     anotherReferenceToTheSamePersonObject.setName("Jerry");8. }怎么了?变量person在第1行中创建,并且在开头时为null。在第2行创建一个新的Person对象,存储在内存中,并为变量person提供对Person对象的引用。那就是它的地址。比方说3bad086a。保存Object的地址的变量person被传递给第3行中的函数。在第4行,你可以听到沉默的声音检查第5行的评论创建一个方法局部变量 - anotherReferenceToTheSamePersonObject - 然后在#6行中产生魔力:变量/引用人被逐位复制并传递给函数内的anotherReferenceToTheSamePersonObject。没有创建Person的新实例。“ person ”和“ anotherReferenceToTheSamePersonObject ”都保持相同的3bad086a值。不要试试这个,但是人== anotherReferenceToTheSamePersonObject会是真的。两个变量都具有引用的IDENTICAL COPIES,它们都引用相同的Person对象,堆上的SAME对象而不是COPY。请注意,anotherReferenceToTheSamePersonObject箭头指向Object而不是指向变量person!如果你没有得到它,那么只要相信我,并记住最好说Java是通过值传递的。那么,通过参考值传递。哦,更好的是传递变量值的副本!;)现在可以随意讨厌我,但请注意,在讨论方法参数时,传递原始数据类型和对象之间没有区别。你总是传递一份参考值的副本!如果它是原始数据类型,则这些位将包含原始数据类型本身的值。如果它是一个Object,那么这些位将包含告诉JVM如何到达Object的地址值。Java是按值传递的,因为在方法中你可以根据需要修改引用的Object,但无论你多么努力,你都永远无法修改将继续引用的传递变量(不是p _ _ _ _ _ _ _)同样的对象无论如何!上面的changeName函数永远不能修改传递的引用的实际内容(位值)。换句话说,changeName不能使Person人引用另一个Object。当然,你可以缩短它,只是说 Java是值得传递的!

慕标琳琳

Java的始终是按值传递,没有例外,永远。那么如何让任何人都对此感到困惑,并相信Java是通过引用传递的,或者认为他们有一个Java作为参考传递的例子?关键是Java 在任何情况下都不会直接访问对象本身的值。对对象的唯一访问是通过对该对象的引用。因为Java对象总是通过引用访问,而不是直接访问,所以通常将字段和变量以及方法参数作为对象进行讨论,而当它们只是对对象的引用时。这种混淆源于这种(严格来说,不正确的)命名法的变化。所以,在调用方法时对于原始参数(int,long等),pass by value是基元的实际值(例如,3)。对于对象,pass by value是对象引用的值。所以,如果你有doSomething(foo)和public void doSomething(Foo foo) { .. }两个FOOS已复制引用指向同一个对象。当然,通过值传递对对象的引用看起来非常像(并且在实践中无法区分)通过引用传递对象。

杨魅力

为了显示对比,请比较以下C ++和Java代码段:在C ++中:注意:错误的代码 - 内存泄漏! 但它证明了这一点。void cppMethod(int val, int &ref, Dog obj, Dog &objRef, Dog *objPtr, Dog *&objPtrRef){     val = 7; // Modifies the copy     ref = 7; // Modifies the original variable     obj.SetName("obj"); // Modifies the copy of Dog passed     objRef.SetName("objRef"); // Modifies the original Dog passed     objPtr->SetName("objPtr"); // Modifies the original Dog pointed to                                 // by the copy of the pointer passed.     objPtr = new Dog("newObjPtr");  // Modifies the copy of the pointer,                                     // leaving the original object alone.     objPtrRef->SetName("objRefPtr"); // Modifies the original Dog pointed to                                      // by the original pointer passed.      objPtrRef = new Dog("newObjPtrRef"); // Modifies the original pointer passed}int main(){     int a = 0;     int b = 0;     Dog d0 = Dog("d0");     Dog d1 = Dog("d1");     Dog *d2 = new Dog("d2");     Dog *d3 = new Dog("d3");     cppMethod(a, b, d0, d1, d2, d3);     // a is still set to 0     // b is now set to 7     // d0 still have name "d0"     // d1 now has name "objRef"     // d2 now has name "objPtr"     // d3 now has name "newObjPtrRef"}在Java中public static void javaMethod(int val, Dog objPtr){    val = 7; // Modifies the copy    objPtr.SetName("objPtr") // Modifies the original Dog pointed to                              // by the copy of the pointer passed.    objPtr = new Dog("newObjPtr");  // Modifies the copy of the pointer,                                    // leaving the original object alone.}public static void main(){     int a = 0;     Dog d0 = new Dog("d0");     javaMethod(a, d0);     // a is still set to 0     // d0 now has name "objPtr"}Java只有两种类型的传递:内置类型的值,以及对象类型的指针值。

翻翻过去那场雪

基本上,重新分配Object参数不会影响参数,例如,private void foo(Object bar) {     bar = null;}public static void main(String[] args) {     String baz = "Hah!";     foo(baz);     System.out.println(baz);}将打印出"Hah!"而不是null。这个工作的原因是因为bar是一个值的副本baz,它只是一个引用"Hah!"。如果它本身就是实际参考,那么foo将重新定义baz为null。
打开App,查看更多内容
随时随地看视频慕课网APP