Trying to fully grasp Java's pass-by-value. Let's say we have this code:
public class Test {
static void switchIt(Test t) {
t = new Test();
}
public static void main(String ... args) {
Test a = new Test();
switchIt(a);
}
}
When the object referenced by a gets passed to switchIt(), the reference value is copied to t. So we'd have two different reference variables, with identical bit-patterns that point to a single object on the heap.
When t = new Test() runs, obviously a still refers to the old object, and t now points to a new object on the heap. Since the a and t reference variables used to have identical bit-patterns, does this mean that Java implicitly changed the bit-pattern of the t reference variable? Or is it wrong to assume that the bit patterns were ever identical to begin with?
Let's say the a reference variable is represented on the stack as 0001. When I pass it to the function, that means t is also represented on the stack as 0001, since I passed a copy of the bits in the reference variable.
When I assign t to a new Test(), if t and a both are represented as 0001 on the stack, would that 0001 change for t?
Think of it this way:
Java isn't passing the object, it's passing the memory pointer of the object. When you create a new object, it gets a new pointer. So when we say java always passes by value, it's because it's always passing the pointer of the object which is a numeric value.
Even though the objects are equal to one another (a.equals(t)) may return true - they are not identical because they have different pointers and are thusly different objects residing in different memory space.
Using your edit example. a would have 0001 but t would be 0002
Is Java "pass-by-reference" or "pass-by-value"?
Hope that helps
Yes, the reference for t would change to point to the newly-allocated Test instance. Your understanding is correct on that point.
When the switchIt() method returns, there are no longer any references to that new object. It is now eligible for garbage collection, while the original object that a continues to reference will not be collectible until main() returns.
I think you got it, but you didn't phrase it too well. Here's a more in depth explanation, though the implementation may not be 100% exactly as I'm describing.
When you compile that code, a structure called a "stack frame" will be created for each of your methods. Each stack frame will hold enough space in it for parameters, local variables and so on. Basically it will have enough resources for your method to do its thing. All these stack frames are placed in "the stack" :)
When you run your code, in main you create a new instance of Test and assign the reference to variable a or, more precisely, to the location in the stack frame reserved for variable a. The actual object will be stored on the heap and your variable a will only hold the memory address of that object, as you already seem to know.
When you call switchIt, the runtime will send a copy of the reference a to the stack frame of the method switchIt. This stack frame has enough space for your parameter and it will store it in its reserved space. But what you're doing in switchIt is replacing the initial value stored in that reserved space with a new reference from a new object that has just been created and placed on the heap. Now you have two objects on the heap, each stack frame containing one of these references.
I think the code will clear you more .Check the hash code in each print statement it is not the memory location but it will help you to understand the answer of your question.
class Ideone
{
static void switchIt(Ideone t) {
System.out.println("Object t "+t); // print statement 2
t = new Ideone();
System.out.println("object t after changing t "+t); // print statement 3
}
public static void main(String[] args) {
Ideone a = new Ideone();
System.out.println("object a "+a); // print statement 1
switchIt(a);
System.out.println("object a after calling switchIt() "+a); // print statement 4
}
}
Output:
object a Ideone#106d69c
Object t Ideone#106d69c
object t after changing t Ideone#52e922
object a after calling switchIt() Ideone#106d69c
print statement 1,2,4 have same hash code but 3 has different hash code.
1. Creating object a
2. Passing a to switchIt(Ideone t):
3. Changing t to new Ideone():
Note:The hash code are not actual memory location.
Related
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 9 months ago.
I'm Ryan who's a rookie in programming. I was going through the OOP part of my textbook today and I found a part that I won't understand at all. There are 2 codes, I'll have them copied here.
The first one is :
public class Change {
public static void main(String[] args) {
int x = 17;
dontChange(x);
System.out.println(x);
}
static void dontChange(int z) {
z = 42;
}
}
When the code was executed. The output would still be 17, which is not the expected 42(in my understanding of parameter and Method.)
The textbook provided another example as well, which results in a change.
public class Change {
void change(Student s) {//student is a type
s.name = "Fred";
public static void main(String[] args) {
stu.name = "Jane";
change(stu);
System.out.println(stu.name);
}
}
This code would result in the output the name as 'Fred', I was wondering where's the difference between them and what was the reason behind these codes when they look similar and worked totally differently.
Thank you for going through the whole post, I wish you have a great day!
You need to distinguish between “passing by value” and “passing by reference”. Maybe this helps
If you want to understand the answer to this Question, why the value does not change, you have to understand, why the value sometimes change.
The values changes,if the Datatyp is referencial. This means, that the data is stored at the heap(a part of memory) and our variable only points to this data. This means, that your variable only stores, where the data is really stored.
If we change our data,we are following our reference and change it there.
This means, that every reference, which points at our data is also changed. It is the same object.
What happens here is different. You are not dealing with referencial Datatyps.
You are dealing with primitives(int, float, char....). Those datatyps aren't stored in the heap. They are stored in the stack(another part of memory). This means, that the data is really stored in our variable. So, if we change our data in our variable, we aren't following an reference and change it there. We are really changing the value in our variable.
An analogy:
Referencial types are like notes, which point to a different note. In the second note is the data. If we try to change the datanote, we take a look at our first note with the reference to the datanote and then change the datanote. Any note pointing to the datanote has now the updated data.
primitives are like, if our first note has all the data. There is no pointing to somewhere else. It is our data
Primitives start most of the time with a lower case letter. Primitives can't have any functions or anything.
Refercal start most of the time with a Capital letter. They can have functions and are most of the time classes
What you wanted to do was to return the new value and set it equal to x.
I hope, i've helped you a bit.
If you have any Questions left, feel free to ask
sorry for my English:)
Firstly, I would point out the difference between the two examples you've shown. The method Change#change(Student)
public class Change {
public void change(Student s) {
s.name = "Fred";
}
}
Compared to Change#dontChange(int)
public class Change {
public void dontChange(int i) {
i = 42;
}
}
The most notable difference between these two methods is where they assign (=) the value they're passing. s.name vs i. Note the presence of the dot operator (.) indicating that there's access of an Object's field or method. This can help start the explanation of why change(Student) updates the value it assigns to as compared to dontChange(int).
There was reference of looking into the difference between pass-by-value and pass-by-reference in other answers, and that will be required information for WHY this happens. However, I think there should be a slightly deeper understanding of what a variable is in java for that to help explain it. The easiest explanation I find is that a variable in java is a number. Period. Always. Now that might seem weird, right? You obviously have an object when you do Student stu = new Student(), but that's only partially correct. You do instantiate (create/construct) an object, but the value stored in Student stu can actually be thought of as a number pointing to a spot in memory where stu's values are stored. There IS a difference in how these number are handled, but they are, in essence, all numbers.
Knowing this, you can work with the thought that values passed to a method in java are always passed-by-value. If you wanted to test this you could see the output of changing the body of Change#change(Student) to
public class Change {
void change(Student s) {
Student newStudent = new Student();
newStudent.name = "Fred";
s = newStudent;
}
}
You may expect the output name to still be "Fred", but it should result in "Jane". We didn't modify the object that Student s refers to, we updated what the variable s points to. The difference being that in the original Change#change(Student) method you assigned the value "Fred" to the name field (s.name) of the object that Student s refers to.
When you call Change#change(Student) with the variable stu the parameter s's value becomes the same identifying number that stu points to, but the variables themselves are entirely different. They only, when s is initialized, have the same value (a number pointing to a space in memory).
It should be noted that assigning "Jane" and "Fred" to the Student's name field is actually assigning a reference to a String which represents "Jane" or "Fred" to the Student's name field. As the name field's type is, assumed to be, String which is not a primitive type. Meaning it's a reference to some String object in memory.
What is happening here is passing by value and passing by reference. In Java all primitive types(int, char...) are passed by value to any method, this means the value of them are copied for the method to use.
Anything else like objects from classes you create are passed by reference. This means the contents of the object are not copied but the address of where that object is in memory is copied to the method. The value at this address(the original object) is then used within the method meaning changes to it are seen outside of the method.
To go into more detail and why this happens can get quite confusing as a beginner but other people have linked good articles to read. To put it simply in my own words.
Whenever you are using an object(non-primitive type) i.e Student. Java is actually seeing this as an address to that object but to keep things easier for the programmer Java doesn't make you declare this in any way. Any access to this object is automatically handled by Java to mean the value of the address you are using.
One source I am studying defines an array as "a collection of variables under one name, where the variables are accessed by index numbers."
But then I realized that you can have an array of objects (or an array of pointers to objects, at least).
This got me to wonder what a variable is defined as in java, as I did not consider an object to be a variable. Jenkov Tutorials cites a variable as being "a piece of memory that can contain a data value."
And since I believe an object fits this definition, is an object considered a variable?
Calling an array a "collection of variables" is arguably stretching the definition already. But an array is certainly a collection of references that can be made to point to different objects in memory, and each such reference can reasonably be called a variable.
Asking "is an object a variable" is a little weird in the first place. In Object o = new Object(), o is clearly a variable, though remember it's a reference to an object in the heap, not the object itself.
Honestly, "variable" is a pretty flexible, ill-defined term -- is a field a variable? The return result of a method? It depends on who's talking and what fuzzy definition they're using today.
is an object considered a variable?
No, these are two distinct things.
The first one (the object) is the value and the second one (the variable) is a way to reference an object, generally to use it (invoking a series of method on it for example).
For example when you write :
new Dog()
You instantiate a Dog. Nice. But suppose you want feed it if it is hungry.
You cannot if you have not a way to chain a series of method on this object.
By storing the reference of the Dog in a dog variable you can do it :
Dog dog = new Dog();
if (dog.isHungry()){
dog.feed();
}
Jenkov Tutorials cites a variable as being "a piece of memory that
can contain a data value."
It says the same thing.
But this :
One source I am studying defines an array as "a collection of
variables under one name, where the variables are accessed by index
numbers."
is rather misleading.
An array is an object that has a state that contains, among other things, elements of the array.
The way which the elements are referenced in is a implementation detail of the Array class and I would not affirm that each element is stored in a specific variable.
An object is created when you call the constructor with the reserved word new.
For example:
Object a = new Object();
a will be the variable of that new object created and will go to reserved memory for that object. You are instantiating that new variable and that variable is associated with that object.
Hope might this will help you to understand it better...
class Bulb
{
private int w;
public void setWattage(int e)
{
w=e;
}
public int getWattage()
{
return w;
}
}
class Test
{
public static void main(String args[])
{
Bulb b[];
b=new Bulb[2];
b[0]=new Bulb();
b[1]=new Bulb();
b[0].setWattage(60);
b[1].setWattage(100);
System.out.println(b[0].getWattage());
}
}
here b[0] and b[1] are reference variables who have the address of two Bulb objects
Class A {
// blah blah
}
Now, whenever we need to create an instance of this class, we do:
A a = new A();
In c++ there are two ways:
1. A a(10); // Created on Stack. Assume that the constructor takes an int argument
2. A a = new A(); // Created on Heap
How do you create user defined Java objects on stack?
No it isn't. All method-local primitive types and references are put on the stack, all objects are put in the heap. No ifs and buts about it.
One reason I can think why they did is that it removes one commonly made error: you pass the stack-based object to a method that stores a reference to that object. Then the object goes out of scope, is removed from the stack, and the reference points to something undefined. Next when you want to access the "object" through the reference, you're in a world of hurt since the object is no longer there - and nobody knows what is.
This question already has answers here:
How do I copy an object in Java?
(23 answers)
Closed 8 years ago.
This might have been asked already but since I am not so sure how to phrase it I could not find it.
Essentially
Suppose we have the class a, (see code below), and we want to copy an instance of it, a1, to another instance a2.
So, in my main I would have a1.copy(a2)
I know that using copy2 method this will work. However copy1 will not. I just would like to clarify why this is. Is it because the parameter is just a "copy" of the object, so the object itself (a2) is not altered.
class a {
private int val;
public class(int val){
this.val = val;
}
public void copy1(a obj){
obj = this;
}
public void copy2(a obj) {
obj.val = this.val;
}
}
The key to understand your problem is that Java's method call is always pass-by-value, not by reference.
When you call a.copy1(b), Java copies a value of b's reference(say it is called b_copy, please note that b_copy points to the same memory location as b), and then pass b_copy to the method copy1.
And in your method of copy1, Java only changes the reference of b_copy.
public void copy1(b_copy){
b_copy=a;
}
So now :
b_copy: b_copy=a;
b: b does not change at all;
When the method ends,b_copy dies. So nothing changes on b!
While a.copy2(b) manipulates on the object itself, but it still copies a new value of b(say b_copy again) and pass into copy2
public void copy2(b_copy){
b_copy.val = a.val;
}
Since b_copy points to the same memory of b, so when you do changes on b_copy.val, you also does the same on b.val itself. That's the reason why b changes.
So now :
b_copy: b_copy, but b_copy's val changes
b: b's val also changes, since b_copy is points to the b's memory location;
And then when method ends, b_copy dies, and b has changed!
You may find more discussion on Is Java "pass-by-reference" or "pass-by-value"?
And you may also need How do I copy an object in Java?
When you call the method copy1(), the parameter is a copy of the reference of the object a obj. When you set it to this (obj = this;) the copy of the reference of the object is replaced by the current object, but the original object and the reference to the object at the place you are calling the copy1() method stays the same. You just change the copy of the reference of the object.
When you call the method copy2(), no reference work is done there, and you are doing one by one matching of the variables (properties of the objects) and there is no copy of reference work there. You are changing the object itself. In this case, this.val = obj.val; would also work.
For more understanding, check this topic and check how other languages like C or C++ handle parameter passing issue.
I think you might want to look into how parameters are passed in Java.
For primitive variables, they are passed by value. If I recall correctly, this means that a temporary value is passed and any changes to the variable in the function update only the temporary variable.
However, objects are passed by reference. This means that instead of the entire object, essentially a pointer to where the object is in memory is passed.
What this means is that updating an object's variables produces lasting effects on that object. Additionally, if you set one object equal to another object, you're really just setting the memory references to be the same (a byproduct of this is that the values of the variables in the objects are then linked).
This explains why the first function fails to do what you want (you're setting the memory locations to be the same). And the second succeeds (you're performing a deep copy into a new memory address).
Your reasoning is correct. When you pass an object to a method (as you do in copy1), all you are doing is creating another reference to the same object. If you override this reference, as copy1 does, it just means that that reference now points to a different object - it does not, and can not, change the original object.
What happens in the memory when a class instantiates the following object?
public class SomeObject{
private String strSomeProperty;
public SomeObject(String strSomeProperty){
this.strSomeProperty = strSomeProperty;
}
public void setSomeProperty(String strSomeProperty){
this.strSomeProperty = strSomeProperty;
}
public String getSomeProperty(){
return this.strSomeProperty;
}
}
In class SomeClass1:
SomeObject so1 = new SomeObject("some property value");
In class SomeClass2:
SomeObject so2 = new SomeObject("another property value");
How is memory allocated to the newly instantiated object and its properties?
Let's step through it:
SomeObject so1 = new SomeObject("some property value");
... is actually more complicated than it looks, because you're creating a new String. It might be easier to think of as:
String tmp = new String("some property value");
SomeObject so1 = new SomeObject(tmp);
// Not that you would normally write it in this way.
(To be absolutely accurate - these are not really equivalent. In the original the 'new String' is created at compile time and is part of the .class image. You can think of this as a performance hack.)
So, first the JVM allocates space for the String. You typically don't know or care about the internals of the String implementation, so just take it on trust that a chunk of memory is being used to represent "some property value". Also, you have some memory temporarily allocated containing a reference to the String. In the second form, it's explicitly called tmp; in your original form Java handles it without naming it.
Next the JVM allocates space for a new SomeObject. That's a bit of space for Java's internal bookkeeping, and space for each of the object's fields. In this case, there's just one field, strSomeProperty.
Bear in mind that strSomeProperty is just a reference to a String. For now, it'll be initialised to null.
Next, the constructor is executed.
this.strSomeProperty = strSomeProperty;
All this does is copy the reference to the String, into your strSomeProperty field.
Finally, space is allocated for the object reference so1. This is set with a reference to the SomeObject.
so2 works in exactly the same way.
Determining Memory Usage in Java by Dr. Heinz M. Kabutz gives a precise answer, plus a program to calculate the memory usage. The relevant part:
The class takes up at least 8 bytes. So, if you say new Object(); you will allocate 8 bytes on the heap.
Each data member takes up 4 bytes, except for long and double which take up 8 bytes. Even if the data member is a byte, it will still take up 4 bytes! In addition, the amount of memory used is increased in 8 byte blocks. So, if you have a class that contains one byte it will take up 8 bytes for the class and 8 bytes for the data, totalling 16 bytes (groan!).
Arrays are a bit more clever. Primitives get packed in arrays, so if you have an array of bytes they will each take up one byte (wow!). The memory usage of course still goes up in 8 byte blocks.
As people have pointed out in the comments, Strings are a special case, because they can be interned. You can reason about the space they take up in the same way, but keep in mind that what looks like multiple copies of the same String may actually point to the same reference.
Points to remember:
When a method is called, a frame is created on the top of stack.
Once a method has completed execution, flow of control returns to the calling method and its corresponding stack frame is flushed.
Local variables are created in the stack.
Instance variables are created in the heap & are part of the object they belong to.
Reference variables are created in the stack.
Ref: http://www.javatutorialhub.com/java-stack-heap.html