Re: How java passes object references?
On Fri, 25 Apr 2008 21:51:44 -0700, pek <kimwlias@gmail.com> wrote:
OK.. Assuming that pass-by-reference means that the following code
would work:
public void swap(Human h) {
h = new Human();
}
Which everybody knows, it doesn't in Java. I'm guessing this works
with C++. Even if it doesn't in C++ (I wouldn't know), I'll be using C=
+
+ as a language that passes by reference for the sake of my questions.=
Now, I know Java passes object references by value, but how exactly
does it do it in memory?
Correct me if I'm wrong anywhere. This is what I think. Suppose we
have the following code: [snip]
Your summary is basically correct (except for your comments about =
C++...it's unfortunate you chose to use as an example a language you don=
't =
know, because it results in you saying wrong things about the language :=
) =
).
The one clarification that I think might help is when you write "allocat=
es =
a small memory block", what we are generally talking about is either a =
local variable that has already been allocated on the stack when the =
method was entered, or a member variable of a class that was already =
allocated either when the class was loaded (for static members) or when =
an =
instance of the class was created (for instance members).
In other words, variables can be stored in a variety of places and while=
=
in some sense they are allocated individually, it's usually more correct=
=
to think of them as being a specific location in a larger block of memor=
y =
that was allocated for a specific purpose (e.g. stack frame, class, =
instance of a class).
The reason I think this is a useful clarification is that when you got t=
o =
the part about how passing by reference might work, it seems you went of=
f =
track at least partly because you didn't understand the nature of the =
above. Specifically (looking at the steps you described for that =
hypothetical passing by-reference language):
[...]
1. Nothing happens, I don't know if this actually works. I don't know
how pointers work in memory.
Whether a language passes by reference or by value, variables still need=
=
to be allocated somehow. Step 1 is the same here as it would be for =
C++ or other languages. If I assume that in your original code example,=
=
"Human h" is a local variable in a method, the storage for that variable=
=
is in a stack frame is created when execution enters the function.
2. Again, memory is allocated for the newly created object and now h
is a pointer pointing at the memory block.
Yes, this step is also the same.
3. When called, the memory location of the passed pointer will copied
to o, thus, both pointing at the same object
This is where you get derailed, because you've made incorrect assumption=
s =
about C++.
One assumption you've made is that C++ handles object construction the =
same way as Java. It doesn't. In particular, C++ doesn't have the same=
=
way of looking at dynamically allocated objects that Java does. A =
variable of type Human isn't going to be a reference to an instance of =
Human. It's going to be an actual Human instance. If you declare that =
as =
a local variable in a function in C++, then the instance will be allocat=
ed =
on the stack.
Another assumption you've made is that C++ uses passing by reference by =
=
default. C++ does support passing by reference, but it's not the =
default. If you want passing by reference, you would need to declare yo=
ur =
method as such:
void change(Human &o)
{
o = new Human();
}
In that case, yes...rather than a copy of the parameter being passed, a =
=
reference to the actual parameter is passed instead. Except that since,=
=
in addition to these other differences, C++ uses the type name to declar=
e =
the actual storage for the instance, you'd be saying that you want to pa=
ss =
a reference to the instance of Human.
A more typical usage in C++ might be something like this:
Type declarations:
class Human
{
// ...
}
// I'm using a typedef to keep the parameter syntax simpler.
// All this does is create a new type that is defined to be
// a pointer to the class Human.
typedef Human *PHuman;
Caller:
PHuman h = new Human();
change(h);
Callee:
void change(PHuman &o)
{
o = new Human();
}
In that example, a reference to the storage used by the "h" variable is =
=
passed to the function, and the compiler translates any usage of the =
parameter "o" to dereference that reference and access the storage =
directly. Thus when the code assigns a new instance of Human to the loc=
al =
parameter "o", that reference to the new instance is actually being copi=
ed =
into the original storage used by "h".
A better comparison might be to use C# instead. C# is much more similar=
=
to Java (it in fact borrows quite a lot from Java), but unlike Java it =
does support passing by reference. In particular, C# has reference type=
s =
the same way that Java does, and so the syntax is a lot more similar.
In particular, in C# the syntax you've shown in your post will do =
_exactly_ the same thing in C# as it would in Java. If you want to pass=
=
by reference, you still need to do so explicitly (as in C++). In C#, it=
=
would look something like this though:
void change(ref Human o)
{
o = new Human();
}
The method would be called like this:
change(ref h);
The "ref" keyword tells the compiler to pass the parameter by reference.=
=
It's required not only in the method declaration itself, but also when y=
ou =
call (this ensures that callers don't find themselves passing something =
by =
reference without knowing it).
4. ??? What happens here???? h and o are both pointers that point to
the same object. If I change o to point to another object, how does h
know about it? What about the previous object?
So, here's the crux of your question I guess. :)
As I mentioned above, the parameter passed by reference isn't a pointer =
to =
the object. It's a pointer to a pointer to the object. That is, it's a=
=
pointer to the variable "h". The pointer is always dereferenced when =
used; that is, in the code you write you never have direct access to the=
=
pointer itself...only to what the pointer points to.
So when you write "o = new Human()" when passing by reference, you're =
not =
actually changing the local variable in the method. The compiler is =
generating code "behind the scenes" that causes the variable that was us=
ed =
as the parameter to be changed instead.
So, right before change() ends the memory allocates: two objects for h=
and o (with no pointers at h, and now it must be garbage
collected....which won't) and....what? Two pointers? Does a pointer
allocate memory?
No new memory allocations are done, other than the one that created the =
=
new instance (i.e. "new Human()").
This is what I was talking about at the top of this article. Assignment=
s =
to local variables, or even to class members, do not allocate memory. =
They simply copy values from one place to another. In this case, the =
value is a reference (pointer) to an instance. In the change() method, =
=
the assignment to "o" has the effect of copying the new instance referen=
ce =
into the original variable that was used as the parameter.
It doesn't change "o", not in the sense that "o" represents your local =
variable. When you pass by reference, the compiler is hiding from you t=
he =
fact that when you write "o", you're actually using "o" as an alias for =
=
the actual parameter.
Am I right about the memory allocations in the Java code? What about
pointers in C++? Do they allocate any memory space? If they don't, how=
does it store the pointers memory location? What are pointers in terms=
of memory?
If you want to know exactly how C++ works, you're probably better off =
posting your question in a C++ newsgroup. That said, C++ isn't really s=
o =
different from Java in basic concept. Ignoring the actual implementatio=
n, =
from a paradigm point of view the main difference is that C++ is always=
=
explicit about its references, whereas Java (and C#) is implicit. C++ c=
an =
have a variable that _is_ a class instance, and a variable that points t=
o =
a class instance has to be declared explicitly (e.g. "Human *h" would =
declare a pointer to an instance of Human). Java cannot have variables =
=
that are class instances; they can only refer to class instance and all =
=
class instances are allocated dynamically (i.e. never on the stack or as=
a =
fully-contained member of some other class, two things that C++ does =
support).
I hope I made my questions as clear as possible. Unfortunately, I
can't post an image to illustrate my point. I'm trying to create a
slide about Pass-by-value, Pass-by-reference and Pass-reference-by-
value. So I need this information in order to create a good
illustration of the concepts (which unfortunately I didn't find
anywhere on the internet).
One of the best descriptions I've seen on the topic is Jon Skeet's artic=
le =
on parameter passing. It's actually written from a C# perspective, but =
=
since Java and C# are so similar, and since C# actually does support =
passing by reference, it may be worth looking at for you:
http://www.yoda.arachsys.com/csharp/parameters.html
In fact, given that Java doesn't support passing by reference, I'm a bit=
=
confused as to why the question wound up here. :) But hopefully the =
above has given some explanation that's useful, which I guess you wouldn=
't =
have gotten if you hadn't posted here (or at least somewhere that I read=
=
:) ). So I can't really complain too much about it. :)
Pete