Re: How java passes object references?
- From: "Peter Duniho" <NpOeStPeAdM@xxxxxxxxxxxxxxxx>
- Date: Fri, 25 Apr 2008 23:21:45 -0700
On Fri, 25 Apr 2008 21:51:44 -0700, pek <kimwlias@xxxxxxxxx> 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 "allocates 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 memory 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 to the part about how passing by reference might work, it seems you went off 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 assumptions 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 allocated 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 your 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 declare the actual storage for the instance, you'd be saying that you want to pass 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 local parameter "o", that reference to the new instance is actually being copied 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 types 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 you 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 used 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. Assignments 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 reference 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 the 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 so different from Java in basic concept. Ignoring the actual implementation, 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++ can have a variable that _is_ a class instance, and a variable that points to 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 article 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
.
- Follow-Ups:
- Re: How java passes object references?
- From: pek
- Re: How java passes object references?
- References:
- How java passes object references?
- From: pek
- How java passes object references?
- Prev by Date: Re: Temp memory needed for CMS heap compaction?
- Next by Date: Re: AspectJ: solution to Java's repetitiveness?
- Previous by thread: Re: How java passes object references?
- Next by thread: Re: How java passes object references?
- Index(es):
Relevant Pages
|