I have the following code which has
a mutable Person class, String and a method to modify the instances of String and Person
class Person{
int a = 8;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
#Override
public String toString() {
return "Person [a=" + a + "]";
}
}
--
public class TestMutable {
public static void main(String[] args)
{
Person p = new Person();
p.setA(34);
String s = "bar";
modifyObject(s, p); //Call to modify objects
System.out.println(s);
System.out.println(p);
}
private static void modifyObject(String str, Person p)
{
str = "foo";
p.setA(45);
}
}
The output is as expected. It prints
bar
Person [a=45]
Now, my question is
What is happening at the place you say str="foo" ?
Initially let's assume that s='bar' and the data resides in 0x100 memory
Now the reference of string is passed to another method, the other method tries to change the contents of the memory location(0x100) to 'foo' using s="foo". Is this what is happening, or is 'foo' is created in differennt memory location ?
Does java pass references by value ?
Java always passes arguments by value NOT by reference.
Let me explain this through an example:
public class Main
{
public static void main(String[] args)
{
Foo f = new Foo("f");
changeReference(f); // It won't change the reference!
modifyReference(f); // It will change the object that the reference variable "f" refers to!
}
public static void changeReference(Foo a)
{
Foo b = new Foo("b");
a = b;
}
public static void modifyReference(Foo c)
{
c.setAttribute("c");
}
}
I will explain this in steps:
1- Declaring a reference named f of type Foo and assign it to a new object of type Foo with an attribute "f".
Foo f = new Foo("f");
2- From the method side, a reference of type Foo with a name a is declared and it's initially assigned to null.
public static void changeReference(Foo a)
3- As you call the method changeReference, the reference a will be assigned to the object which is passed as an argument.
changeReference(f);
4- Declaring a reference named b of type Foo and assign it to a new object of type Foo with an attribute "b".
Foo b = new Foo("b");
5- a = b is re-assigning the reference a NOT f to the object whose its attribute is "b".
6- As you call modifyReference(Foo c) method, a reference c is created and assigned to the object with attribute "f".
7- c.setAttribute("c"); will change the attribute of the object that reference c points to it, and it's same object that reference f points to it.
I hope you understand now how passing objects as arguments works in Java :)
In modifyObject, When you assign to str, you're not mutating str, you're setting it so that it points to a different object. Since it's passed by value, the str pointer local to your modifyObject method is a copy of the s pointer in main, so when you change the former, it does not affect le later.
On the other hand, when it comes to p, the one in modifyObject is still a copy of the one in main, but both pointers refer to the very same object in memory, hence if you call a method on it from modifyObject, you're actually mutating the thing pointed to by p.
Sometimes people get confused when passing by reference. It's possible to change the object that the reference refers to (giving the impression of pass-by-reference), but it is not possible to modify reference itself. So it still remains pass-by-value.
In this function call "modifyObject(s, p);" you are sending the value of variable s to modifyObject method's local variable str. So a new variable is created and its value is changed but the original one remains unchanged.
Related
I have a java pojo class as below
public class ClassA {
private String a;
private String b;
private String c;
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
public String getC() {
return c;
}
public void setC(String c) {
this.c = c;
}
}
And I am using it in another class as below
public class Test {
public static void main(String[] args) {
ClassA ca1 = new ClassA();
ca1.setA("One");
ClassA ca2 = new ClassA();
ca2 = ca1;
System.out.println(ca2);
}
}
The output is: ClassA#53bd815b[a=One,b=<null>,c=<null>]
Is it possible that when I assign ca1 to ca2, ca2 will have only the attribute "a" and not have the other attributes, "b" and "c" as no values are assigned to them?
Your code:
ClassA ca2 = new ClassA();
ca2 = ca1;
… makes no sense. You instantiate a new object of class ClassA. You assign a reference to that object to be stored in a reference variable named ca2. Then you immediately assign another reference to a different object to that same reference variable ca2.
So there was no point to the first of those two lines. Logically, you could replace those two lines with the following, and end up with the same effect.
ClassA ca2 = ca1;
You asked:
is it possible that when I assign ca1 to ca2, ca2 will have only the attribute "a" and not have the other attributes, "b" and "c" as no values are assigned to them.
If you are asking if the second ClassA object can somehow absorb values from the first, the Answer is “No”.
Your two instances of ClassA are separate and distinct from one another. Each holds its own state (member field values). That state is not altered by you assigning a reference to either into a reference variable.
In your Question’s code, you end up with two objects in memory:
One has one member field assigned a value, and the other two yields are null. That object has two reference variables pointing to it.
The other object has all three of its member fields null, with none of the three ever assigned a value. This object has no references left pointing to it. Having no references means this object is effectively “forgotten”, or lost. This object is now a candidate for the garbage collection. After garbage collection, the memory used by this object is freed up to be used for other purposes.
The key concept here is that ca1 and ca2 are not themselves objects. They are reference variables, also known as pointers. They know where to find a particular object. They can each point to different objects, or they can both point to the same object.
See the illustration I made in another Answer of mine on a similar Question.
When you declare ClassA ca2, you are not saying that ca2 is a ClassA, you are saying ca2 will track the location in memory of an object of that class and only that class (and its subclasses).
As for the output of toString being called implicitly by System.out.println, you should override toString yourself to generate whatever output you choose.
I have the following code. I can't, however, understand it's behavior about pass by value and reference.
class Dog{
String name;
int x=100;
Dog(String name){
this.name = name;
}
public String getName(){
return this.name;
}
}
class Demo{
public static void main( String[] args ){
Dog aDog = new Dog("Tom");
foo(aDog);
if (aDog.getName().equals("Tom")) { //true
System.out.println( "Java passes by value."+ aDog.getName());
System.out.println( aDog.x);
} else if (aDog.getName().equals("Taz")) {
System.out.println( "Java passes by reference." );
}
}
public static void foo(Dog d) {
++d.x;
d = new Dog("Taz");
++d.x;
}
}
This will provide output as
Java passes by value.Tom
101
Why is the output 101? I was expecting output 102.
You're incrementing x twice, but on different dogs. Look at this code:
public static void foo(Dog d) {
++d.x;
d = new Dog("Taz");
++d.x;
}
Initially, d refers to the dog with a name of Tom, with x=100. That isn't a copy of the original object - it's a reference to the same object. Java passes the reference by value, which isn't the same as either passing an object by value or passing an object by reference. It's important to understand that the value of aDog in main isn't a Dog object - it's a reference to a Dog object. The value of that reference is passed, by value, to your foo method... so the initial value of d is the same as the value of aDog. Further changes to the d variable itself (rather than the object its value refers to) do not change the aDog variable.
So, looking at the rest of foo:
After the ++d.x, d refers to the dog with a name of Tom, with x=101.
After d = new Dog("Taz"), d refers to a dog with a name of Taz, with x=100.
After the ++d.x, d refers to the dog with a name of Taz, with x=101.
The calling code only ever knows about the dog with a name of Tom, so it prints out Tom 101.
You increment x once, on the dog that was given to the method ("Tom").
Then you create a new dog, called Taz.
You then increment x for that second dog. It won't affect the original one, and both dogs will be at 101.
As for why the calling method still refers to "Tom", even though you changed your local variable to point at "Taz": That's because a local variable is just that: local to the place it is used. The caller does not care about what you do with it later, its own variable will still point at "Tom".
Because Java does not support pass-by-reference or "out parameters", there is nothing the called function can do to change the value of variables in the calling function.
But note that objects are not stored in variables. Only a pointer to them is stored there. The actual object instance itself is in a shared location (the program heap memory). So the called method can indeed change the object. But it cannot assign a different object into the calling function.
Takeaway: Make your local variables final, especially method parameters. Then you cannot reuse the same variable for two different things, and the code becomes less confusing.
Java is always Pass By Value:
main():
Dog aDog = new Dog("Tom"); // {name="Tom", x=100}
foo():
++d.x; // {name="Tom", x=101}
d = new Dog("Taz"); // {name="Taz", x=100}
++d.x; // {name="Taz", x=101}
However, you can get entirely new copy but you need to return it.
In main(): update this line
foo(aDog);
to
aDog = foo(aDog);
also update foo() as:
public static Dog foo(Dog d) {
...
return d;
}
When you use the new keyword like this d = new Dog("Taz");
You create a new Dog, the new Dog it's called Taz and have x=101, so you don't increment d.x 2 times for the same Dog
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is Java pass-by-reference?
Java pass by reference
For the following Java program, my understanding is that a is a reference type to an Integer, like pointer type in C/C++. So any changes done in method f to its value will be reflected after the method returns. But println still prints its original value 0 instead of 3.
Integer and int does not make a difference. Was my previous understanding wrong? Please help. Thank you!
public static void f(Integer b){
b=3;
}
public static void main(String[] args){
Integer a=0;
f(a);
System.out.println(a);
}
Java always passes arguments by value NOT by reference.
Let me explain this through an example:
public class Main
{
public static void main(String[] args)
{
Foo f = new Foo("f");
changeReference(f); // It won't change the reference!
modifyReference(f); // It will modify the object that the reference variable "f" refers to!
}
public static void changeReference(Foo a)
{
Foo b = new Foo("b");
a = b;
}
public static void modifyReference(Foo c)
{
c.setAttribute("c");
}
}
I will explain this in steps:
Declaring a reference named f of type Foo and assign it to a new object of type Foo with an attribute "f".
Foo f = new Foo("f");
From the method side, a reference of type Foo with a name a is declared and it's initially assigned to null.
public static void changeReference(Foo a)
As you call the method changeReference, the reference a will be assigned to the object which is passed as an argument.
changeReference(f);
Declaring a reference named b of type Foo and assign it to a new object of type Foo with an attribute "b".
Foo b = new Foo("b");
a = b is re-assigning the reference a NOT f to the object whose its attribute is "b".
As you call modifyReference(Foo c) method, a reference c is created and assigned to the object with attribute "f".
c.setAttribute("c"); will change the attribute of the object that reference c points to it, and it's same object that reference f points to it.
I hope you understand now how passing objects as arguments works in Java :)
Integer (like other "basic" classes) are inmutable objects. It means that there is no method by which you can change the value. If you do
new Integer(1);
the object created will always hold the 1 value.
Of course you can do
Integer a = new Integer(1);
a = new Integer(2);
but here what you are doing is creating two objects, and assigning a to each of them in turn.
When calling the method, you are passing a copy of the reference in a (as edalorzo said), so you are doing pretty much the same (but without changing the original a reference).
Of course, lots of classes are not inmutable. In these classes, you would have one (or several) methods that allow you to change the object inner state, and (as long as you are accessing the same object) these changes would be "shared" by all the references of the object (since they all point to the same one). For example, suppose Integer had a setValue(int) method, then
public static void f(Integer b){
b.setValue(3);
}
public static void main(String[] args){
Integer a=0;
f(a);
System.out.println(a);
}
Would work as you expected.
The method receives a copy of the reference. The assignment doesn't change the value that the integer represents (it couldn't even if it wanted to - Integer is immutable in Java). It is just setting b to point at something else. The original Integer object that a is pointing to is unaffected by this change.
Before b = 3;
------ ------
| a | | b |
------ ------
| |
------------
|
Integer(0)
After b = 3;
------ ------
| a | | b |
------ ------
| |
| |
| |
Integer(0) Integer(3)
If you wanted to change the value you'd have to use a mutable type instead.
Related
Does Java have mutable types for Integer, Float, Double, Long?
Integer is immutable so the passing by reference won't work as expected. see Java : Best way to pass int by reference
In Java everything is pass-by-copy, in your method you are chaining the reference, not the actual object it is pointing to.
Your understanding was right but Integers are immutable. If you want to affect the value of a Integer variable, the only way is to create a new Integer object and discard the old one. For this reason, the statement b=3 has no effect.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Is Java pass by reference?
public class myClass{
public static void main(String[] args){
myObject obj = new myObject("myName");
changeName(obj);
System.out.print(obj.getName()); // This prints "anotherName"
}
public static void changeName(myObject obj){
obj.setName("anotherName");
}
}
I know that Java pass by value, but why does it pass obj by reference in previous example and change it?
Java always passes arguments by value, NOT by reference. In your example, you are still passing obj by its value, not the reference itself. Inside your method changeName, you are assigning another (local) reference, obj, to the same object you passed it as an argument. Once you modify that reference, you are modifying the original reference, obj, which is passed as an argument.
EDIT:
Let me explain this through an example:
public class Main
{
public static void main(String[] args)
{
Foo f = new Foo("f");
changeReference(f); // It won't change the reference!
modifyReference(f); // It will change the object that the reference refers to!
}
public static void changeReference(Foo a)
{
Foo b = new Foo("b");
a = b;
}
public static void modifyReference(Foo c)
{
c.setAttribute("c");
}
}
I will explain this in steps:
1- Declaring a reference named f of type Foo and assign it to a new object of type Foo with an attribute "f".
Foo f = new Foo("f");
2- From the method side, a reference of type Foo with a name a is declared and it's initially assigned to null.
public static void changeReference(Foo a)
3- As you call the method changeReference, the reference a will be assigned to the object which is passed as an argument.
changeReference(f);
4- Declaring a reference named b of type Foo and assign it to a new object of type Foo with an attribute "b".
Foo b = new Foo("b");
5- a = b is re-assigning the reference a NOT f to the object whose its attribute is "b".
6- As you call modifyReference(Foo c) method, a reference c is created and assigned to the object with attribute "f".
7- c.setAttribute("c"); will change the attribute of the object that reference c points to it, and it's same object that reference f points to it.
I hope you understand now how passing objects as arguments works in Java :)
In Java, an object handle, or the identity of an object is considered a value. Passing by value means passing this handle, not a full copy of the object.
A "reference" in the term "pass by reference" also doesn't mean "reference to an object". It means "reference to a variable" – a named "bucket" in a function definition (or, rather, a call frame) that can store a value.
Passing by reference would mean the called method could change variable values in the calling method. (For example, in the C standard library, the function scanf works this way.) This isn't possible in Java. You can always change the properties of an object – they aren't considered a part of its "value". They're completely different independent objects.
It did not change obj (your code doesn't change it anyway).
Had it been passed by reference, you could have written:
public static void changeName(myObject obj){
obj = new myObject("anotherName");
}
And have "anotherName" printed by the main method.
You're changing a property of obj, not changing obj (the parameter) itself.
The point is that if you pointed obj at something else in changeName that that change would not be reflected in main.
See this post for further clarification.
It is passing the reference to obj as a value (a bit confusing I know :)).
So let's say it makes a copy of the pointer to obj's value and pass that.
That means that you can do things like:
public static void changeName(myObject obj){
obj.setName("anotherName");
obj = new myObject();
}
and the statement
System.out.print(obj.getName());
is still going to refer to the old object (the one that you did setName).
Java is passing a copy of what you're passing to your function. When it is a primitive type - it will be the copy of a value. When it is an object - you're passing the reference copy. In you're code example you're modifying one of objects properties, but not the reference itself so the name will be changed. However when you'd like to assign new object to obj variable in changeName function, then you're changing reference, so outside obj will have an old value.
public class testtype
{
private int a;
private double b;
testtype(int a,double b)
{
this.a=a;
this.b=b;
}
public void maketoequal(testtype oo)
{
oo.a=this.a;
oo.b=this.b;
}
void trytoequal(int c)
{
c=this.a;
}
public static void main(String[] args)
{
testtype t1,t2;
t1=new testtype(10,15.0);
t2=new testtype(5,100.0);
t1.maketoequal(t2);
System.out.println("after the method is called:"+"\n"+"the value of a for t2 is:"+t2.a
+"\n"+"the value of b for t2 is :"+t2.b);
int c=50;
t1.trytoequal(c);
System.out.println("the value of c after the method be called is:"+c);
}
}
why the c is not changed?
Java passes parameters by value (so a copy of the value is made and used locally in the method).
For a primitive type -- c in your case --, the value is the value of c, so your using a copy of the value of c and you don't change c
For an object the value is the value of the reference so even if you pass it by value (copy it) it still references the same object and you can change the object using your copy of the reference...
Java is strictly pass-by-value
Because primitive parameters are passed by value to the method, and so the value you change is local to the method.
You probably want
c = thistest.getA()
where getA() returns the value of a.
In java, parameters are passed by value, not by reference, so what you are doing in "trytoequal" won't work.
See these explanations on java variables value: http://www.yoda.arachsys.com/java/passing.html
Primitive datatypes are passed by value and not by reference, meaning that the c you get in "trytoequal" is a variable whose scope is just within the method and its value is a copy of the method parameter.
The value of c in the method is changed, and then discarded.