If I have a member variable such as this (declared in the body of a class)
private Dot[] dots=new Dot[numDots];
I loop through all members of this array, and:
1) Pass every Dot object to a function of another class, which:
2) Passes it to yet another function of a 3rd class, if some conditions are met
3) And the 3rd class changes some properties of the Dot object
then when this object is returned to the original/parent class, would those changes to its properties have retained? Or would it be treated like a local variable by the 2nd/3rd functions?
Yes, the changes to the properties are retained. Java is 100% pass-by-value, however, when you pass an object, the "value" passed is truly a pointer to the object. Thus, when you change an object in a method, you're changing the actual object passed in.
That is, if you have the following method, then the calling method will see the changes:
private void updateMyDot(final Dot aDot) {
aDot.dotColor = new Color(255,255,255);
}
but if you do the following, then the calling method will not see the changes.
private void updateMyDot(/* not final */ Dot aDot) {
aDot = new Dot();
aDot.dotColor = new Color(255,255,255);
}
In the second example, the caller will not see any changes and will not see the newly created Dot object.
Objects are passed by [reference value where the value is the reference] (things that inherit from Object), primitive values (int, long, double, etc.) are passed by value.
This means that when a primitive is passed from a caller to method it is copied, whereas with an object a [value of the] reference is passed.
Which in turn means that when an object is mutated by a method the caller sees those changes because it has a reference to the same object.
Conversely when a method mutates a primitive the caller does not see the changes as the method is working on a copy.
[reason for the edits]
If Java had pass by reference then you could do this:
Object x;
x = new Integer(42);
foo(x);
System.out.println(x.getClass()); // pass by reference would have it print out java.lang.Float
where foo is defined as:
void foo(Object o)
{
o = new Float(43);
}
Since Java passes the reference by value o = new Float(43); is allowed - but the value in the caller will remain as the new Integer(42);
Related
I read in this question that Java is always pass-by-value. And so even references are passed by value.
I don't understand what this means, can somebody clarify this for me please?
Given this
Object ref = new Object();
ref is actually storing a value, some address to an object. Let's say 1234.
When you pass ref around
public void method(Object passed) {...}
...
method(ref);
Java actually copies the value of the reference and assigns it to the parameter. So, passed will also have the value 1234.
Similarly, if you had
Object otherRef = ref;
the value 1234 would be copied and assigned to otherRef.
If you then re-assign otherRef, like
otherRef = new Object();
that would assign a new value to otherRef, but ref would still have the same value as before. That's what pass by value is.
When you call a method
ref.toString();
Java uses the value of the reference to find the referenced object and invoke the method. This is called dereferencing.
You might want to go through the JPDA javadoc, starting with StackFrame. Go through the fields and types and you'll start to understand how everything is mapped. For example, it has a getValues(..) method which returns a Map<LocalVariable, Value>. That should tell you that a variable doesn't actually store anything. Instead, it is mapped to a value, where that value may be all sorts of things.
int a = 5;
public void foo(int num) {
num = num + 5;
System.out.println(num);
}
foo(a);
System.out.println(a);
In the above code, a is passed into foo() by value. That means that a new variable is created with the scope of foo() that has the same initial value as a. When the value of num is changed, the value of a is not changed. The first println() will print a 10, the second will print a 5. In c++ you could pass a in by reference, which means that the value of a would be changed too.
I can try, in some other languages you have the option of passing something by a pointer (e.g. a reference to a memory region). Java calls every function with a value (not a pointer), but the value of an Object is a reference to a memory region. See also the default toString() in your own classes.
I always find this a good example:
Dog foo = new Dog("Rocky");
modifyDog(foo);
System.out.println(foo.name); //Alice
public void modifyDog(Dog aDog)
{
aDog.name = "Alice"; //here you change the field 'name' of the object located in memory currently referenced by foo and aDog variables.
aDog = new Dog(); //since aDog is a copy of foo then this won't recreate foo object
}
Ok bit of an odd question. I have the following code, which just creates a simple java object called DumObj and sets a string value using a setter method. Then a few methods are called from a TestBed class using the DumObj as a parameter.
I initially thought that calling TestBed.updateId(DumObj) would not affect my DumObj, and the initial value of ID that was set to "apple" would stay the same. (Because of the whole pass-by-value thing)
However the value of ID was set to the updated value of "orange". Ok I thought, that's weird, so I wrote another method, TestBed.setToNull(DumObj). This method just sets DumObj to null, so when I call the getId() method I was expecting to get a null pointer exception.
However the output I got was the value of ID still set to "orange".
Code is as follows :
public static void main(String[] args)
{
TestBed test = new TestBed();
DumObj one = new DumObj();
one.setId("apple");
System.out.println("Id : " + one.getId());
test.updateId(one);
System.out.println("Id : " + one.getId());
test.setToNull(one);
System.out.println("Id : " + one.getId());
}
public void updateId(DumObj two)
{
two.setId("orange");
}
public void setToNull(DumObj two)
{
two = null;
}
Output is as follows :
Id : apple
Id : orange
Id : orange
It's probably something really simple I'm overlooking, but can someone explain this behaviour to me? Is Java not pass-by-value?
When you write
DumObj one = new DumObj();
it's important to realise that one is not a DumObj - it's a reference to DumObj, and references are passed by value.
So you're always passing by value, and you can change the passed reference (so your passed reference now points to a different object). However, your object itself could be mutable, so this:
one.setValue(123);
will change the referenced object. When you call this:
public void setToNull(DumObj two)
{
two = null;
}
you're changing the passed reference (remember - it's been passed by value and is local to the method!) and so your original object and original reference are not affected.
When you do:
two = null;
You are only setting the two variable reference to null. The object that it was pointing to still exists, and is referenced by one.
On the other hand, when you do:
two.setId("orange");
You are modifying the object that is referenced by both one and two.
Java is kind-of "pass reference by value" for objects. So in setToNull(DumObj two), two is a reference to an object. If you say two = null;, that now makes two a reference to not an object; it doesn't change the object. If, on the other hand, you do something like two.setId("blue"), you are changing the object that two references.
When you call updateId the new reference variable two and old reference variable one both referring to same object in heap so changing one gets reflected in other reference variable.
now when you call setToNull again new reference variable two and old reference variable one both referring to same object.But here when you do two = null only reference variable two point to null object. but reference variable one still pointing to same object.When you do two==null ,you are not changing any value in object referred by it but instead you are referring reference variable to null.
In case in setToNull method you write two=new DumObj(); then a new object in heap will be created and two will point to this new object .and then for ex if you write
two.setId("banana");
and in your main code if you write one.getId() inside syso then it will print orange not banana.
hope i helped.
Yes, Java is pass by value. But your variables are really pointers to the object allocated on the heap. So what its passed by value is the pointer, not the object.
In your examples:
public void updateId(DumObj two)
{
two.setId("orange");
}
The first passes the variable (pointer) by value, that is, updateId() recieves a copy of the pointer. But what you are doing here is to modify the object pointed by the pointer. So the object was modified when you return to the caller function.
public void setToNull(DumObj two)
{
two = null;
}
In the second case, you are assigning null to a copy of the original pointer, not the original pointer itself, so that function call has no effect at all in the origial variable.
I have come across two scenarios.
One in which an array is passed as argument to a method and if it is updated in the called method, it is reflecting in the calling method as well.
But in the second scenario, a String Object is passed as argument. The object is updated in the called method, but it doesn't reflect in the calling method.
I want to understand what is the difference between two, even though in both cases, value (of reference) is passed as argument. Please see below snippets.
Scenario 1:
class Test {
public static void main(String[] args){
int a[] = {3,4,5};
changeValue(a);
System.out.println("Value at Index 1 is "+a[1]);
}
public static void changeValue(int b[]){
b[1] = 9;
}
}
Output:
Value at Index 1 is 9
Here, reference (Memory Address) related to array a is passed to changeValue. Hence, b is just pointing to same address as a does.
Hence, whether I say b[1] or a[1], it is referring to same memory address.
Scenario 2:
public class Test {
public static void main(String[] args){
String value = "abc";
changeValue(value);
System.out.println(value);
}
public static void changeValue(String a){
a = "xyz";
}
}
Output:
abc
If I apply the same logic here, String Object VALUE's reference (Memory Address) is being passed to changeValue, which is recieved by a.
Hence, now a should be referring to the same memory location as VALUE does. Therefore, when a="xyz" is executed, it should replace "abc" with "xyz".
Can someone please point out where my understanding goes wrong? Thanks in advance!!
Java passes all its arguments by value. This means that a copy of the pointer to the String is made, and then passed to the method. The method then makes the pointer point at another object, but the original pointer still points to the same String.
This is not the same thing:
in the first example, you pass an array reference as an argument, therefore you correctly expect it to be changed by manipulating the reference directly;
in the second example however, you pass an object reference, sure -- but you change the reference itself in the method. Changes to a are not reflected when the method returns.
Consider any object:
public void changeObj(Object o)
{
o = new Whatever();
}
a new object is created, but it won't change o in the caller. The same happens here.
You're doing different things; with the string you set the parameter value, with the array you set something belonging to the reference.
For an equivalent array example you'd need to try setting the array reference to a new array:
public static void changeValue(int[] b) {
b = new int[] { 42, 60 };
}
The original array won't be changed.
The difference here is simple, and it is not actually about immutability of strings, as some other answers (now edited or deleted) might have originally implied. In one version (with the string), you have reassigned the reference, and in other version (with the array), you haven't.
array[0] = foo; // sets an element, no reassignment to variable
array = new int[] { 1,2,3 }; // assigns new array
obj = "hey"; // assigns new value
When you reassign the variable, you are not going to observe that change outside of the method. When you change elements of an array without reassigning the array variable, you will observe those changes. When you call a setter on an object without reassigning the actual variable of the object, you will observe those changes. When you overwrite the variable (new array, assigning new value, creating new object, etc.) those changes will go unobserved.
Arguments are passed (or copied) by value. The variable inside the method has the same value as the variable on the outside at the beginning. The variables are not linked, and they are not aliases for one another. They just happen to contain the same value. Once you reassign the value to one of them, that is no longer true! The variable on the outside is not affected by the variable on the inside, or even another local variable. Consider
Foo foo = new Foo();
Foo other = foo;
foo.setBar(1);
int bar = other.getBar(); // gets 1
foo = new Foo();
foo.setBar(42);
int bar2 = other.getBar(); // still gets 1
foo and other only referenced the same object for a time. Once foo was assigned a new object, the variables no longer had anything in common. The same is true for your reassignments to the parameter variable inside your method.
Thank you all for answers and updates..
I understood the difference between scenario 1 and 2 as below..
In scenario 1, the array reference is passed. The called method just updates one of the elements pointed by the reference.
While in scenario 2, the reference is passed, but when the called method assigns "xyz" to the reference variable (pointer), it actually creates a new String Object and its reference is assgined to a local reference variable 'a' (Pointer now points a different objct).
The code in called method is as good as
a = new String("xyz");
Hence, the object in called method and calling method are absolutely different and indepenedent and have no relation with each other.
The same could have happened with scenario 1, if instead of doing
b[1] = 9;
I would have used
b = new int[] {8,9,10};
I understood, Mutability fundamentals would have come in action, if I might have done like below..
String a="abc";
a="xyz";
In this case, object "abc" was being pointed by 'a'. When 'a' is assigned the duty to point to a new object "xyz", a new object "xyz" is created, which is not replacing the existing object "abc". i.e. "abc" is still existing but has no reference variable to keep itself accessible anymore. This non-replacement property is because of Immutability of String.
Please advice why primitives being used as method's parameters do a copy of its value while objects are used as is?
In Java, all arguments are passed by value - but in the case of reference types (i.e. everything other than a primitive) the value of a variable isn't the object itself - it's a reference to the object. Thus that reference is copied into the method's parameter, so it refers to the same object.
Note that this doesn't just apply to method calls:
StringBuilder x = new StringBuilder();
StringBuilder y = x; // Copy the value of x, which is a *reference*
y.append("Hello");
System.out.println(x); // Prints "Hello"
Here, x and y refer to the same object, even though they're separate variables. Thus when the contents of that object is changed via the append call through the y variable, the change is visible via the x variable too.
I think of it as being a bit like giving someone the address of your house: if I give two people my home address, and one of them paints the door red, then when the second person visits the house, they'll see the red door too. I'm not giving them my house itself, I'm giving them a way of getting to my house.
There are many, many articles about this - although unfortunately some will claim that objects are passed by reference in Java. They're not - the references are passed by value, as I said above. Scott Stanchfield has a good article about this, amongst many others.
To expand on what Jon Skeet said, primitive types are usually quite small - a double is 8 bytes. Objects, on the other hand, can be HUGE, and so passing a reference to them saves time and stack space versus copying the whole thing. Plus this allows you to modify the contents of the Object.
That's what it looks like but is not. Java is always pass by value.
When you declare something like this:
Date aDate = new Date();
The variable aDate is not really an object, but an object reference. When you pass that object reference to another method, a "copy" of that reference is passed ( just like with primitives a copy of the value is passed )
Now, since those two copies "reference" the same underlaying object, you see that sending a message on one of them affects the other, but if you change the reference to assign a new one, the other doesn't change.
For instance:
class Some {
int data = 0;
}
class Other {
void doSomething( Some o ) {
o.data = 10;
}
void change( Some a ) {
a = new Some();
a.data = 1024;
}
}
class Main {
public static void main( String [] args ) {
// create an object and get its object reference
Some original = new Some();
System.out.println( original.data ); // prints 0
// now pass it to a method from the class "Other"
Other o = new Other();
other.doSomething( original );
System.out.println( original.data ); // prints 10, because data was changed in "doSomething"
// To probe that the reference is not passed, but a copy of it
// invoke the "change" method.
other.change( original );
System.out.println( original.data ); // remains 10, instead of 1024.
// the value 1024 was changed in the new reference, and the one passed along
// didn't change. It still refers to the original object.
}
}
I hope this helps
I am not sure about some things in OOP.
If I have Class1, which has some private field, for example private Field field1, and make
getField1 () {
return field1;
}
then I have some class with constructor
public Class2 (Field field) {
someMethod(field);
}
And then I call constructor of Class2 in Class3 like:
Class2 cl = new Class2(instanceOfClass1.getField1());
And now the question: Am I working with field1 of instanceOfClass1 in someMethod(field)?
This depends on whether field is a value or a reference.
Value types are copied when passed as parameters. Reference types are not; the function is simply handed a "reference" that points back to the original value, and any changes that it makes are reflected in the original value.
Whether a given type is value or reference depends on your particular programming language. Generally speaking, basic integer and boolean types are usually value types, and everything else is up in the air -- some languages make strings values, and others treat them as references, etc.
Edit: Since you mentioned you're using Java, here's a short program that demonstrates value and reference types:
class ClassOne {
public int myInt;
}
class ClassTwo {
public int myInt;
public ClassTwo(ClassOne c)
{
myInt = c.myInt;
c.myInt = 3;
}
}
public class main
{
public static void main(String[] args)
{
ClassOne c = new ClassOne();
c.myInt = 1;
System.out.println("C1: " + c.myInt);
ClassTwo c2 = new ClassTwo(c);
System.out.println("C2: " + c2.myInt);
System.out.println("C1: " + c.myInt);
}
}
Running this program will give the output:
C1: 1
C2: 1
C1: 3
In this program, both ClassOne and ClassTwo contain an integer field -- a value type. ClassTwo takes a ClassOne parameter -- a reference type -- in its constructor, and sets its own integer field based on the value of the ClassOne object it is given, and then changes the ClassOne object's value.
Because classes are reference types, changing the ClassOne object in the ClassTwo constructor causes the original object to be changed. (In the main function here, that's c.) But because integers are value types, even though c2 changes the value of c.myInt in its constructor, because it sets its own value beforehand, c2.myInt isn't affected: it retains the original number, because it was copied rather than referenced.
Hopefully this helps clear things up a bit.
You're working with the value contained in it. If it is a mutable object then yes, it is possible to change the state of the instance of Class1 from outside, which violates data protection principles. This is why you should copy mutable types before returning them.
I had to reread your question two or three times to make sure I understood what you're asking.
To recap:
There is Class1 which contains an field attribute (of type Field?) which is sent back by it's getField1() method.
There is then Class2 which is apparently has a constructor that accepts an object parameter of Field type and contains a method that uses an instance of Field to trigger a local method in this class.
You then use a third class to instantiate Class2 and initialize it using an instance of Field using the getField1() method from an instance of Class1.
In the case of Java, providing you've done the necessary instantiation this would mean that the Field instance in Class1 is being used throughout the process. You can verify this using a System.out.println() (this will give you an # symbol with a series of weird numbers) or using the a.equals(b) method common to all objects.
Here is an interesting link about passing objects by value:
http://www.javaranch.com/campfire/StoryPassBy.jsp