Example is a Card class with a swap() method. Two Card objects are instantiated. The method swaps them by declaring a third Card variable, but without instantiating a third object. The third variable is used as the temp holder to support a swap. I expected the swap not to work, because the temp variable refers to the first object, then the first object is assigned the second object, and the second object is assigned temp, which picks up the change to the first object, according to my assumptions.
public class Tester
{
public static void main(String[] args)
{
Card[] cards = new Card[2];
cards[0] = new Card('x');
cards[1] = new Card('y');
System.out.println( cards[0].getVal() + "\n" + cards[1].getVal() + "\n" );
Card.swap(cards);
System.out.println( cards[0].getVal() + "\n" + cards[1].getVal() + "\n" );
}
}
//Card class --------------------------------------------------------------------
class Card
{
private char value;
public Card(char value)
{
set(value);
}
public static void swap(Card[] cards){
Card temp = cards[0];
cards[0] = cards[1];
cards[1] = temp;
}
public boolean set(char value)
{
this.value = value;
return true;
}
public char getVal()
{
return value;
}
}
Output:
x
y
y
x
I expect cards[0] and cards[1] to refer to the memory that was referred to by cards[1] before temp is assigned to cards[1]. I expect the dereference of cards[0] to be lost.
The actual result is that cards[0] is swapped with cards[1]. (Is this a true copy, or a reference switch?) My understanding was that, since all Java variables are references, temp's dereference would become cards[1] when cards[0]'s dereference became cards[1]. Now it looks like temp has its own memory, even though it was not assigned a heap object in a "new" operation. I read elsewhere something that suggested to me that this is how method variables work, but I couldn't find anything that confirmed that it is how method variables of a user-defined type, or any non-primitive type, work.
Card temp = cards[0];
cards[0] = cards[1];
cards[1] = temp;
The reference of 'card X' object (held by the 0 position of the array) is assigned to 'temp' variable.
Then the reference of 'card Y' object (held by the 1 position of the array) is assigned to the 0 position of the array.
Then the reference of 'card X' object (held by 'temp' variable) is assigned to the 1 position of the array.
Later when you dereference the reference that the array holds in its 0 position you get the 'card Y' as expected.
A reference in the context of Java is not like references in C or C++. In Java your are rather dealing with pointers, and these pointers are pass-by-value.
Therefore there is also no automatic copying of objects (which you assumed) and after your swap there are still only two Card objects, the same ones you created before calling the method.
The answers and comments to the question Is Java “pass-by-reference” or “pass-by-value”? might help understanding this.
Related
I was doing some exercises on arrays, and I was prompted to return a reference to an array after copying it element by element. What does this exactly mean?
My code is the following:
public static int[] cloneArray(int array[])
{
int[] arraycopy = new int[array.length];
for(int i = 0; i < array.length; i++)
{
arraycopy[i] = array[i];
}
return arraycopy;
}
I don't know what I should be returning though as a "reference": should I return an array of ints or an int? Whenever I try to print the array, I get a weird combination of characters and numbers (unless I invoke Arrays.toString()).
"Return a reference to an array" just means "return an array".
Java only returns values, which are either primitives or object references (ie for objects, the value is a reference).
Although Java is based on C, it doesn't sully itself with pointers etc like C does.
In Java, arrays and objects do not act like primitive types such as int. Consider the following code:
public class MyClass {
public static int method1(int ar[]) {
int x = ar[1];
ar[1] = 3;
return x;
}
}
Now suppose that somewhere else, the follow code is executed:
int abcd[] = new int[3];
abcd[0] = 0;
abcd[1] = 1;
abcd[2] = 2;
int d = MyClass.method1(abcd);
System.out.println(abcd[1]);
What would be printed? It's not 1, but 3. This is because the method was not given the data in the array, it was told the location of the array. In other words, it was passed a reference. Because it was using a reference, changing the value of an array index changed its value in the code that called it. This would not have happened if method1 had taken an int as an argument.
Basically, in Java, methods do not accept arrays as arguments or return arrays. They only use references to arrays. The same goes for objects (except for Strings, which are passed by value).
In Java, Objects are only accessed by reference. Just return the Array object.
I'm not terribly familiar with Java, I'm fiddling with a simple binary tree and ran into something that I dont understand...
in the following snippet, Add() passes AddHelper() a number and a reference to the root node, mRoot. However, mRoot is always null, even after the first call to AddHelper()
If, however, I change I change AddHelper() such that it uses mRoot directly (instead of being passes in by reference), then it works... I dont understand why/how this would be any different, functionally.
Node mRoot;
public void Add( int num ) {
AddHelper(num, mRoot);
}
private void AddHelper( int num, Node node ){
// if I change 'node' to 'mRoot', it works. why?
if ( node == null ) {
node = new Node(num);
}
else {
...
}
assuming you have declared mRoot as a Node in your class already let me answer your question.
java is always pass by value when you pass mRoot to your method you are passing bytes that are referring the object in the heap. for example when you do this with a primitive variable
int i =5;
int j=i;
the bytes stored in i is transferred to j. similarly when you do this
Object obj = new Object();
Object newObj = obj;
the bytes stored in the reference variable obj is getting transferred to the reference newObj. as obj holds the reference to the Object instance the same reference is held by newObj.
you can see that
i = 5;
j=i;
j=10; // this doesn't change the i value
same way
obj = new Object();
newObj = obj;
newObj = new Object(); // this doesn't change the obj
hope you understood.
EDIT:
to answer your question in the comment, consider the following code.
class Sample {
Object originalObj;
public static void main(String[] args) {
System.out.println(originalObj); // prints null
tryToCreateInstance(originalObj);
System.out.println(originalObj); // still prints null
createInstance(originalObj)
System.out.println(originalObj); // prints the object hashcode
originalObj = returnInstance(originalObj);//returns the same reference as originalObj
//is already initialized, if it had been null
// this would have returned a new object
System.out.println(originalObj); // prints the object hashcode
}
public void tryToCreateInstance(Object obj1){
if(obj1==null) {
obj1 = new Object(); // relate this with my answer above
// this wont change what originalObj refers
}
}
public void createInstance(){
if(obj==null) {
originalObj = new Object(); // refers to the instance variable originalObj
// hence will affect what originalObj refers
}
}
public Object returnInstance(Object obj1) {
if(obj1==null) {
return new Object(); // returns a new object
}
else {
return obj1;
}
}
}
This is because you are not setting mRoot in your first case. Even though you are setting a node to new Node(num);, you are not setting mRoot. To set mRoot:
if ( node == null ) {
node = new Node(num);
this.mRoot = node; //depending on your logic
}
else {
...
}
Jave is pass by value always. For example, mRoot points to Object X. When you pass mRoot to AddHelper, now node will point to Object X. And then you re-initialize node to new Object (say Object Y). But the previous mRoot still points to Object X.
Hence you need to set mRoot back to Object Y.
When we say pass by value, for primitives the value is copied. But in case of Objects, the object reference is copied (but not the object is duplciated). So if you pass a String reference to a function, the function argument will point to the same String only (as it has copied the object reference which can be though of as a pointer)
I have a Long object in a class, I give it a value and then I pass it to another class' constructor, where it is changed. Why are the changes NOT visible in the first object?
The code:
public class ClassA {
private Long t;
public ClassA() {
t = new Long(10);
System.out.println(t); // prints 10
new ClassB(t); // it is modified (see ClassB)
System.out.println(t); // prints 10 again
}
public static void main(String[] args) {
new ClassA();
}
}
class ClassB {
private Long p;
public ClassB(Long p) {
this.p = p;
this.p = this.p + 1;
System.out.println(this.p); // prints 11
}
}
The output is: 10 11 10
The Long variable is initialized in ClassA. Then I pass it to ClassB, modify it and clearly the changes are not visible in the first class. Why?
It is because the Long class is immutable; once an instance is created, it can never change.
In this line:
this.p = this.p + 1;
what you are doing is create a new Long object. Other examples of immutable classes include all "wrapper" classes for primitive numeric types (Byte, Short etc) and String.
What doesn't help is that it makes the + operator unintuitive; what really does not help is that the language allows + on all of these immutable classes.
What happens in the above line could be written as (although it happens differently in the bytecode, I suspect):
long tmp = this.p.longValue();
tmp += 1;
this.p = new Long(tmp);
You can also verify immutability by marking your p as final in class B, which means the reference p can never change; this.p = this.p + 1 will raise a compile error since you attempt to modify reference p.
this line this.p = this.p + 1; does not modify p, it creates a new Long from adding the two values p and 1 and then sets this.p to be a reference to this new Long. Objects of the class Long do not have mutator methods so they can never change (within Class B this.p was not changed, this.p became a reference to a new Long)
So the behaviour is actually
this.p=p;
Long newLong=this.p + 1;
this.p=newLong;
What you're imagining is
this.p=p
this.p.imaginaryAddLocal(1);
this would effect the original p, but of course this method imaginaryAllLocal doesn't exist because objects of the class Long are immutable
To begin with, Long is immutable. It means you cannot change the value that you set in the constructor (note the absence of set methods).
When you do
this.p = this.p + 1;
Java does.
1) Autoconvert this.pto its long value (primitive)
2) Arithmetic operation
3) Autoconvert the result back to a new, different Long and assign the reference to this.p
t continues pointing, all the time, to the original Long object.
In Java, you modify objects through its attributes (not adviceable, you should make them private) or its methods. A + (or other operator) will never change an object state (although it may create a new one, in the only case of myString1 + myString2)
1- You are just modifying the p member of class B
2- Everything is passed by value (and not by reference) in Java
The Long class is immutable, so you can not pass back the value by modifying it in the called function. In your ClassB a copy is created and the original value is never changed.
If you want the caller to see the changed value, you must pass it back as return value.
The same is true for the other primitive wrappers and String.
Because Java uses pass-by-reference. This means that it passes a copy of the variable, and not a reference to the "original" one.
E.g. in C++, you can do this:
void change_var(int &x)
{
x = 2;
}
int x = 10;
change_var(x);
std::cout << x << std::endl;
This would print 2, since the reference to the variable x is being passed, and not a copy.
I have been through this question on legality of forward references but not clear as to what is meant by forward references in Java language . Can someone please explain with the help of an example ?
This is specifically a compilation error. And its all about ordering of class variable declarations. Let's use some code for illustrative purposes:
public class ForwardReference {
public ForwardReference() {
super();
}
public ForwardReference echoReference() {
return this;
}
public void testLegalForwardReference() {
// Illustration: Legal
this.x = 5;
}
private int x = 0;
// Illustration: Illegal
private ForwardReference b = a.reference();
private ForwardReference a = new ForwardReference();
}
As you can see, Java allows you to reference a class variable in a class method, even if the declaration of the variable comes after the method. This is an example of a (legal) forward reference, and support for this is built into the Java compiler.
What you cannot do though, is declare a class variable 'a' that depends on another class variable 'b' that has not been declared yet. Dependent class variable declarations must appear in reverse order of their dependency.
On a tangent, Most, if not all IDE's will warn you if your code contains illegal reference errors.
Illegal forward references are covered in section 8.3.2.3 of the JLS.
It's basically just the order that things are read by the compiler, if you have
int c = 3
int a = b;
int b = 5;
the compiler will read it from top to bottom, so it will se the first line, which declares a variable 'c', and assigns it to 3, and that is fine, then it will encounter the second line, which declares a variable 'a', and then tries to assign it to 'b'.
But now, the compiler has a problem: What is this 'b' thing? It has only yet learned about 'c', and just recently 'a', but it has no knowledge anything called 'b', since to the compiler, it has not yet been declared. So then, since the compiler can't handle all the confusion, it stops, and leaves you to figure what you have done to anger it.
So, the forward reference part would be a reference to something that does not yet exist. Forward in time perhaps..
In simple terms it means referencing (accessing a variable, calling a function) that is further down in the code file.
static int x=getY();
static int y=5;
static int getY() { return y; }
x's value is set to the result of getY()
getY() is called before y's value is set to 5
x's value is therefore 0 (default integer)
y's value is 5
public class AnyCode {
void print() {
System.out.println("Value of j - " + j); // legal
System.out.println("Value of i - " + i); // legal
}
// CASE - 1
int k = i; // illegal
int i;
// CASE - 2
int l = j; // legal
static int m = j; // illegal
static int j;
// CASE - 3
A aObj = bObj; // illegal
B bObj = new B();
public static void main(String[] args) {
/*
Note :- here anyCode act as a local variable and get space on stack
whereas the object it is referring to is present on heap. And you
cannot forward reference a local variable.
*/
anyCode.print(); // 'Cannot find symbol' error
AnyCode anyCode = new AnyCode();
}
}
class A {
}
class B {
}
*********Refer CASE - 1*********
Forward referencing instance variable is not allowed as compiler is not sure of the type of value we are forward referencing or it might even be possible that no such variable exist.
Consider an example :-
int a = b;
boolean b = false;
If forward referencing is allowed in above case then it might create a havoc.
int a = b; // What is b? is it a primitive variable or a value or a object reference
in the above example i have decided not to declare b and now if such assignment were allowed by java, then it will be a nightmare.
**********Refer CASE - 2*********
Static variables are loaded before instance variables and hence forward referencing static variables and assigning them to instance variable is perfectly fine
This is the code I have, please look at it before you read the question
package ict201jansem2012;
public class Qn3b {
public static void main(String[] args) {
int a = 1;
int b[] = {4,5};
String s = "Good luck!";
method1(b[1]);
System.out.println("(1) b[0] = "+b[0]+"; b[1] = "+b[1]);
method2(b);
System.out.println("(2) b[0] = "+b[0]+"; b[1] = "+b[1]);
method3(a);
System.out.println("(3) a = " + a );
method4(s);
System.out.println("(4) s = " + s );
}
public static void method1(int b) {
b = 7;
}
public static void method2(int[] b) {
b[0] = 3;
}
public static void method3(int a) {
a = 3;
}
public static void method4(String s) {
s = "UniSIM";
}
}
Output:
(1) b[0] = 4; b[1] = 5
(2) b[0] = 3; b[1] = 5
(3) a = 1
(4) s = Good luck!
So my question is ,
This is intresting for me to know as learning programmer. The int b array 0 index value has changed, but not the other variables like the String s and int a. Before i ran this program I roughly thought in my mind that the variable will change their values as the methods are called ,this is because the method is being called and the main method vairable such as a,s and b array are passed and then they are being modified.
So in a nutshell why is that the b array 0 index is changed while the other variables are not changed?
Because you said you were a beginner programmer, I'll do a little writeup to explain (or try to explain) exactly what is happening.
It is because you are passing an argument to your method1 - method4 methods
These arguments, themselves, are references to other objects.
When you use the assignment operator, an equals sign, you overwrite that reference for the value in the current scope - where variables can be 'seen'.
In your code:
In the case of method1 you are creating a new reference, the variable can only be seen within that scope. That is, when you then go b = << expr >> you are assigning the variable b within method1's scope the value, not b in the main scope. The same is true of your method3 and method4 methods, you are assigning a new value to the respective variables within that scope, as you are creating new references rather than altering the original objects.
But, method2's code behaves differently, this is because you are mutating the object inside that code. You are altering the object directly - rather than creating a new reference inside that scope.
Consider the code below
int[] array = new int[] {1, 2};
public void test()
{
method1(array);
System.out.println(array[0] + ", " + array[1]);
method2(array);
System.out.println(array[0] + ", " + array[1]);
}
// because we are working with objects, the identifier, can be different to the arrays identifier
// in this case, I've chosen to use 'a' instead of 'array' to show this
public void method1(int[] a)
{
// this mutates the array object
a[0] = 2;
}
public void method2(int[] array)
{
// this overwrites the method2.array but not the global array
array = new int[] { 1, 2, 3 };
}
We create a new array, with identifer 'array' in the global scope. (In Java, this would be the classes own scope)
In method1, we take an argument, which is the same object being passed as the global array object, so when we mutate it, both objects will change. So, the first print statement will be
"2, 2"
Where array[0] has been altered
N.B. Because we dealing with objects, the 'name' of the variable doesn't matter - it will still be a reference to the same object
However, in method2, we take an argument, like in method1, but this time we use the assignment operator to assign that variable to a new value in the scope that it's currently in - so the global array isn't altered, so we still print out
"2, 2"
For a beginner programmer, I would personally write a few test programs where you get to fully understand how variables and scopes work.
But just know, everytime you create a new block of code, a new scope is created, local variables to that scope can only be seen in that scope and ones below it.
For instance:
public void test()
{
int a = 5;
method1(a);
System.out.println(a); // prints 5
}
public void method1(int a)
{
// a is only viewable in the method1 scope
// and any scopes below it, that is, any scopes created within method1
// and since we use an assignment operator, we assign method1.a a value, not global 'a' a value
a = 123;
if (true)
{
// this is a new scope, variables created in this block cannot be seen outside it
// but can see variables from above it
System.out.println(a); // prints 123
}
}
Here, we create a new scope inside method1 inside the if statement, which can see a above it. However, because method1 and test's scopes are both independent, when we use the assignment operator, we assign the value of a to the local scope. So a is different in both test and method1
I hope you understand better now.
I'm not very good at conveying things, but if it even helped a little bit in understanding scopes I did well, plus, it was fun.
Java is pass-by-value, but most values (everything that's not a primitive, in this case int[] and String) are references, which means they act like pass-by-reference.
Here's a nice writeup: http://javadude.com/articles/passbyvalue.htm
arrays are special type of objects and memory will be allocated on HEAP. When you pass array as parameter to method it will be pass as reference-value (copy of the reference).
This means initial b and this new reference points to same object. Unless new reference points to another object, changes on this reference will reflect on same object. That is why you are seeing value reflected on original array.
All of the values were passed TO the inner methods, but the inner methods returned nothing. However, method2 modified the internal value of the array that was passed to it, so that inner value appeared modified on return.
Note that method2 is the only one where you did not assign to the variable (parameter) itself, but rather assigned to an element of the object whose reference was passed in.
There is a critical difference between modifying the reference (pointer) to an object, and modifying the object itself.