标签云

微信群

扫码加入我们

WeChat QR Code


I believe that much of the confusion on this issue has to do with the fact that different people have different definitions of the term "reference". People coming from a C++ background assume that "reference" must mean what it meant in C++, people from a C background assume "reference" must be the same as "pointer" in their language, and so on. Whether it's correct to say that Java passes by reference really depends on what's meant by "reference".

2018年12月16日39分18秒

I try to consistently use the terminology found at the Evaluation Strategy article. It should be noted that, even though the article points out the terms vary greatly by community, it stresses that the semantics for call-by-value and call-by-reference differ in a very crucial way. (Personally I prefer to use call-by-object-sharing these days over call-by-value[-of-the-reference], as this describes the semantics at a high-level and does not create a conflict with call-by-value, which is the underlying implementation.)

2018年12月16日39分18秒

Gravity: Can you go and put your comment on a HUGE billboard or something? That's the whole issue in a nutshell. And it shows that this whole thing is semantics. If we don't agree on the base definition of a reference, then we won't agree on the answer to this question :)

2018年12月16日39分18秒

I think the confusion is "pass by reference" versus "reference semantics". Java is pass-by-value with reference semantics.

2018年12月15日39分18秒

Gravity, while you're absolutely correct in that folks coming from C++ will instinctively have a different intuition set regarding the term "reference", I personally believe the body is more buried in the "by". "Pass by" is confusing in that it is absolutely distinct from "Passing a" in Java. In C++, however it colloquially is not. In C++ you can say "passing a reference", and it's understood that it will pass the swap(x,y) test.

2018年12月16日39分18秒

Isn't it slightly confusing the issue with internal details? There's no conceptual difference between 'passing a reference' and 'passing the value of a reference', assuming that you mean 'the value of the internal pointer to the object'.

2018年12月15日39分18秒

But there is a subtle difference. Look at the first example. If it was purely pass by reference, aDog.name would be "Fifi". It isn't - the reference you are getting is a value reference that if overwritten will be restored when exiting the function.

2018年12月15日39分18秒

Lorenzo: No, in Java everything is passed by value. Primitives are passed by value, and object references are passed by value. The objects themselves are never passed to a method, but the objects are always in the heap and only a reference to the object is passed to the method.

2018年12月16日39分18秒

My attempt at a good way to visualize object passing: Imagine a balloon. Calling a fxn is like tieing a second string to the balloon and handing the line to the fxn. parameter = new Balloon() will cut that string and create a new balloon (but this has no effect on the original balloon). parameter.pop() will still pop it though because it follows the string to the same, original balloon. Java is pass by value, but the value passed is not deep, it is at the highest level, i.e. a primitive or a pointer. Don't confuse that with a deep pass-by-value where the object is entirely cloned and passed.

2018年12月16日39分18秒

What's confusing is that object references are actually pointers. In the beginning SUN called them pointers. Then marketing informed that "pointer" was a bad word. But you still see the "correct" nomenclature in NullPointerException.

2018年12月16日39分18秒

This is why the common refrain "Java doesn't have pointers" is so misleading.

2018年12月16日39分18秒

You are wrong, imho. "Keeping in mind that myDog is a pointer, and not an actual Dog, the answer is NO. myDog still has the value 42; it's still pointing to the original Dog." myDog has value 42 but its name argument now contains "Max", rather than "Rover" on // AAA line.

2018年12月15日39分18秒

Think about it this way. Someone has the address of Ann Arbor, MI (my hometown, GO BLUE!) on a slip of paper called "annArborLocation". You copy it down on a piece of paper called "myDestination". You can drive to "myDestination" and plant a tree. You may have changed something about the city at that location, but it doesn't change the LAT/LON that was written on either paper. You can change the LAT/LON on "myDestination" but it doesn't change "annArborLocation". Does that help?

2018年12月16日39分18秒

Scott Stanchfield: I read your article about a year ago and it really helped clear things up for me. Thanks! May I humbly suggest a little addition: you should mention that there is actually a specific term that describes this form of "call by value where the value is a reference" that was invented by Barbara Liskov for describing the evaluation strategy of her CLU language in 1974, in order to avoid confusion such as the one your article addresses: call by sharing (sometimes called call by object-sharing or simply call by object), which pretty much perfectly describes the semantics.

2018年12月16日39分18秒

Gevorg - The C/C++ languages don't own the concept of a "pointer". There are other languages that use pointers but do not allow the same types of manipulation of pointers that C/C++ allow. Java has pointers; they're just protected against mischief.

2018年12月16日39分18秒

+1 Nice stuff. good diagrams. I also found a nice succinct page here adp-gmbh.ch/php/pass_by_reference.html OK I admit it is written in PHP, but it is the priciple of understanding the difference that I think is important (and how to manipulate that difference to your needs).

2018年12月16日39分18秒

Eng.Fouad It's a nice explanation but if a points to the same object as f (and never gets its own copy of the object f points to), any changes to the object made using a should modify f aswell (since they are both working with the same object), so at some point a must get its own copy of the object f points to.

2018年12月15日39分18秒

MrD when 'a' points to the same object 'f' also points to, then any change made to that object via 'a' is also observable via 'f', BUT IT DID NOT CHANGE 'f'. 'f' still points to the same object. You can totally change the object, but you can never change what 'f' points to. This is the fundamental issue that for some reason some people just can't comprehend.

2018年12月15日39分18秒

MikeBraun ...what? Now you've confused me :S. Isn't what you just wrote contrary to what 6. and 7. shows?

2018年12月16日39分18秒

This is the best explanation I've found. By the way, what about the basic situation? For example, the argument requires an int type, does it still pass the copy of an int variable to the argument?

2018年12月16日39分18秒

Do you mean pointers?.. If I get it correctly, in public void foo(Car car){ ... }, car is local to foo and it contains the heap location of the Object? So if I change car's value by car = new Car(), it will point to different Object on the heap? and if I change car's property valu by car.Color = "Red", the Object in the heap pointed by car will be modified. Also, it is the same in C#? Please reply! Thanks!

2018年12月16日39分18秒

domanokz You're killing me, please don't say that word again! ;) Note that I could have answered this question without saying 'reference' as well. It's a terminology issue and 'p's make it worse. Me and Scot have different views on this unfortunately. I think you got how it works in Java, now you can call it pass by-value, by-object-sharing, by-copy-of-the-variable-value, or feel free to come up with something else! I don't really care as long as you got how it works and what's in a variable of type Object: just a PO Box address! ;)

2018年12月16日39分18秒

Sounds like you just passed a reference? I'm going to championing the fact that Java is still a copied pass-by-reference language. The fact that it is a copied reference doesn't change the terminology. Both the REFERENCES still point to the same object. This is a purist's argument...

2018年12月16日39分18秒

I guess Java designed with pointers in mind. Otherwise, why NullPointerException exists? Nevertheless, for this wonderful explanantion, getting pointers will just make it complicated

2018年12月16日39分18秒

So drop in on theoretical line #9 System.out.println(person.getName()); what will show up? "Tom" or "Jerry"? This is the last thing that will help me hurdle this confusion.

2018年12月16日39分18秒

Since the values of the primitives are immutable (like String), the difference between the two cases is not really relevant.

2018年12月16日39分18秒

Exactly. For all you can tell via observable JVM behavior, primitives could be being passed by reference and could live on the heap. They don't, but that's not actually observable in any way.

2018年12月16日39分18秒

primitives are immutable? is that new in Java 7?

2018年12月15日39分18秒

CarlosHeuberger, "primitives are immutable?". The point is that you can pretend that 'primitives' are actually (mutable) references to immutable objects.

2018年12月15日39分18秒

Pointers are immutable, primitives in general are mutable. String is also not a primitive, it is an object. Moreover, the underlying structure of the String is a mutable array. The only immutable thing about it is the length, that being the inherent nature of arrays.

2018年12月16日39分18秒

But the thing that keeps getting repeated "you can't change the value of objects passed in arguments" is clearly false. You may not be able to make them refer to a different object, but you can change their contents by calling their methods. IMO this means you lose all the benefits of references, and gain no additional guarantees.

2018年12月15日39分18秒

I never said "you can't change the value of objects passed in arguments". I will say "You can't change the value of the object reference passed in as a method argument", which is a true statement about the Java language. Obviously you can change the state of the object (as long as it's not immutable).

2018年12月16日39分18秒

Keep in mind that you cannot actually pass objects in java; the objects stay on the heap. Pointers to the objects can be passed (which get copied onto the stack frame for the called method). So you never change the passed-in value (the pointer), but you're free to follow it and change the thing on the heap to which it points. That's pass-by-value.

2018年12月16日39分18秒

Sounds like you just passed a reference? I'm going to championing the fact that Java is still a copied pass-by-reference language. The fact that it is a copied reference doesn't change the terminology. Both the REFERENCES still point to the same object. This is a purist's argument...

2018年12月16日39分18秒

Java does not pass an object, it passes the value of the pointer to the object. This creates a new pointer to that memory location of the original object in a new variable. If you change the value (the memory address it points to) of this pointer variable in a method, then the original pointer used in the method caller remains unmodified. If you are calling the parameter a reference then the fact that it is a copy of the original reference, not the original reference itself such that there are now two references to the object means that it is pass-by-value

2018年12月16日39分18秒

However, you should have followed up with a more complex example where a function appears to alter a variable to whose address it has a reference.

2018年12月16日39分18秒

People are not "dancing around the real issue" of stack vs heap, because that's not the real issue. It's an implementation detail at best, and downright wrong at worst. (It's quite possible for objects to live on the stack; google "escape analysis". And a huge number of objects contain primitives that probably don't live on the stack.) The real issue is exactly the difference between reference types and value types -- in particular, that the value of a reference-type variable is a reference, not the object it refers to.

2018年12月16日39分18秒

It's an "implementation detail" in that Java is never required to actually show you where an object lives in memory, and in fact seems determined to avoid leaking that info. It could put the object on the stack, and you'd never know. If you care, you're focusing on the wrong thing -- and in this case, that means ignoring the real issue.

2018年12月15日39分18秒

And either way, "primitives go on the stack" is incorrect. Primitive local variables go on the stack. (If they haven't been optimized away, of course.) But then, so do local reference variables. And primitive members defined within an object live wherever the object lives.

2018年12月15日39分18秒

Agree with the comments here. Stack/heap is a side issue, and not relevant. Some variables may be on the stack, some are in static memory (static variables), and plenty live on the heap (all object member variables). NONE of these variables can be passed by reference: from a called method it is NEVER possible to change the value of a variable that is passed as an argument. Therefore, there is no pass-by-reference in Java.

2018年12月16日39分18秒

+1 I would also add Dog **objPtrPtr to the C++ example, that way we can modify what the pointer "points to".

2018年12月15日39分18秒

This is one of the best answers I have seen so far. It mostly avoids the irrelevant semantics argument of "reference vs value of the reference" present elsewhere and instead discusses the mechanics of what actually happens. I had to give most other "pass-by-value" answers -1 because of their self-contradictory or factually false content, but this one gets +1 instead.

2018年12月16日39分18秒

But this doesn't answer for the given question in Java. As the matter of fact, everything in Java's method is Pass By Value, nothing more.

2018年12月15日39分18秒

As simple as that !

2018年12月16日39分18秒

I would rather say that bar is a copy of the reference baz (or baz alias), that points initially to the same object.

2018年12月16日39分18秒

I like this distinction in nomenclature. It's unfortunate that Java supports call by sharing for objects, but not call by value (as does C++). Java supports call by value only for primitive data types and not composite data types.

2018年12月15日39分18秒

I really don't think we needed an extra term - it's simply pass-by-value for a specific type of value. Would adding "call by primitive" add any clarification?

2018年12月16日39分18秒

Call by Sharing

2018年12月15日39分18秒

So I can pass-by-reference by sharing some global context object, or even passing a context object that contains other references? I still pass-by-value, but at least I have access to references I can modify and make them point to something else.

2018年12月15日39分18秒

Colloquially called a pointer.

2018年12月15日39分18秒

Gevorg - Then what is a "NullPointerException"?

2018年12月16日39分18秒

Hot: A unfortunately named exception from before Java settled on a clear terminology. The semantically equivalent exception in c# is called NullReferenceException.

2018年12月15日39分18秒

It's always seemed to me that the use of "reference" in Java terminology is an affectation that hinders understanding.

2018年12月15日39分18秒

I learnt to call these so called "pointers to objects" as an "handle to the object". This reduced ambiguity.

2018年12月16日39分18秒

In java when you say "In java everything is reference" you mean all objects are passed by reference. Primitive data types are not passed by reference.

2018年12月15日39分18秒

I am able to print swapped value in main method. in trickey method , add the following statement arg1.x = 1; arg1.y = 1; arg2.x = 2; arg2.y = 2; so, as arg1 now holding of pnt2 refrence and arg2 holding now pnt1 reference, so, its printing X1: 2 Y1: 2 X2: 1 Y2: 1

2018年12月15日39分18秒

In a language with pass-by-reference, the thing which is passed (the reference) is ephemeral; the recipient is not "supposed" to copy it. In Java, passing an array is passed is an "object identifier"--equivalent to a slip of paper which says "Object #24601", when the 24601st object constructed was an array. The recipient can copy "Object #24601" anywhere it wants, and anyone with a slip of paper saying "Object #24601" can do anything it wants with any of the array elements. The pattern of bits that is passed wouldn't actually say "Object #24601", of course, but...

2018年12月16日39分18秒

...the key point is that the recipient of the object-id that identifies the array can store that object-id wherever it wants and give it to whomever it wants, and any recipient would be able to access or modify the array whenever it wants. By contrast, if an array were passed by reference in a language like Pascal which supports such things, the called method could do whatever it wanted with the array, but could not store the reference in such a way as to allow code to modify the array after it returned.

2018年12月16日39分18秒

Indeed, in Pascal you can get the address of every variable, be it passed-by-reference or locally copied, addr does it untyped, does it with type, and you can modify the referenced variable later (except locally copied ones). But I don't see the point why you would do that. That slip of paper in your example (Object #24601) is a reference,its purpose is to help find the array in memory, it does not contain any array data in itself. If you restart your program, the same array might get a different object-id even if its content will be the same as it has been in the previous run.

2018年12月16日39分18秒

I'd thought the "" operator was not part of standard Pascal, but was implemented as a common extension. Is it part of the standard? My point was that in a language with true pass-by-ref, and no ability to construct a non-ephemeral pointer to an ephemeral object, code which holds the only reference to an array, anywhere in the universe, before passing the array by reference can know that unless the recipient "cheats" it will still hold the only reference afterward. The only safe way to accomplish that in Java would be to construct a temporary object...

1970年01月01日00分03秒

...which encapsulates an AtomicReference and neither exposes the reference nor its target, but instead includes methods to do things to the target; once the code to which the object was passed returns, the AtomicReference [to which its creator kept a direct reference] should be invalidated and abandoned. That would provide the proper semantics, but it would be slow and icky.

2018年12月16日39分18秒

+1 for the swap test -- probably the most straightforward and relatable way to distinguish between passing by reference and passing a reference by value. Iff you can easily write a function swap(a, b) that (1) swaps a and b from the caller's POV, (2) is type-agnostic to the extent that static typing allows (meaning using it with another type requires nothing more than changing the declared types of a and b), and (3) doesn't require the caller to explicitly pass a pointer or name, then the language supports passing by reference.

2018年12月15日39分18秒

"..for primitive datatypes you will work with an copy and for objects you will work with an copy of the reference to the objects" - perfectly written!

2018年12月16日39分18秒

Thank you for beginning with a discussion of the definitions of the terms. That sets your answer apart from the crowd and is necessary for a proper understanding.

2018年12月16日39分18秒

I find your second-to-last sentence very misleading. It's not true that "all objects in Java are references". It's only the references to those objects that are references.

2018年12月15日39分18秒

i understood with this answer

2018年12月16日39分18秒

This is the clearest, simplest way to see that Java passes by value. The value of obj (null) was passed to init, not a reference to obj.

2018年12月16日39分18秒

So it's byRef in regards to objects and byVal in regards to primitives?

2018年12月15日39分18秒

mox please read: Objects are not passed by reference, this is a ledgend: String a=new String("unchanged");

2018年12月15日39分18秒

public void changeit(String changeit){changit = "changed";} changeIt(a); assert(a.equals("unchanged"));

2018年12月15日39分18秒

This is yet another great example of the fallacy of the "it is not pass by reference" semantics argument. This answer says right in the bold, first sentence: "only references are passed." Either a reference is passed, or a reference is not passed. You just said yourself that a reference is passed. By saying "it is not passed by reference since a reference is passed but..." you are trying to make a point by mangling English.

2018年12月16日39分18秒

Aaron "Pass by reference" does not mean "pass a value that is a member of a type that is called a 'reference' in Java". The two uses of "reference" mean different things.

2018年12月16日39分18秒

"pass by copy" is what pass-by-value means.

2018年12月16日39分18秒

+1. What C does support, is treating references (which C calls pointers) as first-class values, and then passing them by value.

2018年12月15日39分18秒

Yeah, in C you can create pointers not only on objects, but on arbitrary variables - so you can easily simulate "call-by-reference" of any variable. In Java this works only for variables which have a surrounding object, which you can give.

2018年12月15日39分18秒

I think it is very close to my understanding of Java object and its reference. Object in Java is passed to a method by a reference copy (or alias).

2018年12月15日39分18秒

I think you nailed it by saying you can't change the reference from the object itself

2018年12月15日39分18秒

So an object can be changed by using its public interfaces but could not be replace with sth else i.e deference and by this java achieves best of both worlds

2018年12月16日39分18秒