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)
Related
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.
In the following code why output is 0 42 42 rather than 0 0 42.
In Java object is not passed by reference so why value of t.x was modified to 42?
class Two
{
byte x;
}
class PassO
{
public static void main(String [] args)
{
PassO p = new PassO();
p.start();
}
void start()
{
Two t = new Two();
System.out.print(t.x + " ");
Two t2 = fix(t);
System.out.println(t.x + " " + t2.x);
}
Two fix(Two tt)
{
tt.x = 42;
return tt;
}
}
Because what's being passed around in Java is the value of the pointer to the object. Thus when you do tt.x=42, you are changing the original t.x to have a value of 42. And when you return tt you are actually returning the same pointer, so infact t and t2 point to the same instance of the object.
In Java object is not passed by reference so why value of t is
modified to 42?
The value of t is not modified to 42. t.x is modified to 42.
Java is always pass-by-value. The difficult thing to understand is
that Java passes objects as references and those references are passed
by value.
Yes it is passed by value. The value is the reference. t is a pointer to a new Two(). You pass the value that t is referring too and point to it with tt.
Your method fix is not really testing passed by value adherence. If you were really testing for passed by value adherence the method should be something like below:
Two fix(Two tt)
{
// Create a brand new instance of Two
Two newTwo = new Two();
newTwo.x = 42;
// Assign the new reference to the passed in value.
tt = newTwo;
return tt;
}
In your original fix method you are just mutating the passed in object.
I have written a code -
// Node Class
class aNode {
// Node Contents
int NodeInt;
char NodeChar;
// constructor
aNode() {
}
aNode(int x, char y) {
NodeInt = x;
NodeChar = y;
}
}
class MainClass {
static aNode node = new aNode();
public static void main(String[] args) {
node = null;
function(node);
if (node == null) {
System.out.println("Node is null");
}
}
static void function(aNode x) {
if (x == null) {
System.out.println("Node is null");
}
x = new aNode(5, 'c');
System.out.println(x.NodeInt);
System.out.println(x.NodeChar);
}
}
I expected the output to be -
Node is null
5
c
but when the program returns to main, the value of node is set to null again. So I get the output to be -
Node is null
5
c
Node is null
Please help me modify the code to get desired output. Any help will be appreciated!
You should know, that aNode node and aNode x are references to different objects. It is one of Java features - passing only by value. It mean, that when you are calling
function(node);
you are not passing node reference to method function(...), you are creating new reference to the same object. But in line
x = new aNode(5,'c');
you are setting reference x to new object. So, node still references to null and x references to new aNode.
To get more about passing params in Java, read next article.
Reference data type parameters, such as objects, are also passed into
methods by value. This means that when the method returns, the
passed-in reference still references the same object as before.
However, the values of the object's fields can be changed in the
method, if they have the proper access level.
Real pass-by-reference is impossible in Java. Java passes everything by value, including references..
So you have to slightly change your code to get the desired output:
class aNode{
//Node Contents
int NodeInt;
char NodeChar;
//constructor
aNode(){
}
aNode(int x, char y){
NodeInt = x;
NodeChar = y;
}
}
class JavaApplication8{
static aNode node = new aNode();
public static void main(String[] args){
node = null;
node=function(node);
if(node == null){
System.out.println("Node is null");
}
}
static aNode function(aNode x){
if(x == null)
{
System.out.println("Node is null");
}
x = new aNode(5,'c');
System.out.println(x.NodeInt);
System.out.println(x.NodeChar);
return x;
}
}
Output:
Node is null
5
c
You are passing a static object, but in the method function(), you are not changing the value of object node. You are changing the value of other object only. So in main, the value of node s null only.
In general, this is because Java passes a copy of the reference to the aNode object to your method. Changing this reference will not change the original reference.
Inside function(), x is simply a local variable. When you reassign a reference in Java, you are modifying the content of the reference itself, not the one of the referred object. There's no way in Java to pass the address-of an object. If you want such a behavior, you can try with a generic class like Wrapper
In my original code, I'm adding nodes to a tree. My goal is to somehow get access to the last node that I added in the tree (my idea was to create another object that will point to the last object (node in my original example)).
public class RandomSubClass
{
int firstNum;
}
import java.util.LinkedList;
public class RandomClass
{
LinkedList<RandomSubClass> myListOfObjects = new LinkedList<RandomSubClass>();
void addItem(int firstNum, RandomSubClass toBeReturned)
{
RandomSubClass o1 = new RandomSubClass();
o1.firstNum = firstNum;
myListOfObjects.add(o1);
// Here I was thinking that 'toBeReturned' will get same address as
// 'o1', and by changing 'toBeReturned' (in main), values in 'o1' change
//
toBeReturned = o1;
// This following commented code worked,
// but I can't use it in my original code.
//
// The reason I can't use it is because when I add a node to a tree,
// I start at the root and trace the new node's way to a new leaf,
// which makes it hard to do (simply) that.
//
//toBeReturned.firstNum = firstNum;
//myListOfObjects.add(toBeReturned);
}
}
public class Main
{
public static void main(String[] args)
{
RandomClass myList = new RandomClass();
RandomSubClass r1 = new RandomSubClass();
RandomSubClass r2 = new RandomSubClass();
myList.addItem(1, r1);
myList.addItem(2, r2);
// I would like to do that, and see changes in the node in 'myList'
//
r1.firstNum = 10;
r2.firstNum = 20;
}
}
I want to check something about the node after I add it to the tree, and if it satisfies some condition, I want to change a flag for that node.
I can re-trace the node again (starting at root), but my tree might get huge at some point and it will take time. So if I get the address of that node when I add it, and after I check my condition, I can modify the flag at that address, knowing that it will change the flag at that node (last added).
Yes, you can do this. I give you permission. :-) But your example code won't work because Java objects are passed by value, not by reference. That is, when you pass an object to a function, if you reassign that object, it has no effect on the caller. For example:
void caller()
{
String s1="Hello";
updateString(s1);
System.out.println(s1);
}
void updateString(String s1)
{
s1="Goodbye";
}
The output of this function is "Hello", NOT "Goodbye". The assignment within the updateString function does not change the value passed in by the caller.
There are (at least) three ways to do what you want.
Method 1: The simplest is to return the new object, rather than updating a parameter:
SomeObject addItem(int firstnum)
{
SomeObject o1=new SomeObject();
o1.firstnum=firstnum;
objectList.add(o1);
return o1;
}
...
void callingFunction()
{
SomeObject newObject=addItem(1);
newObject.secondnum=2;
... etc ...
}
I prefer this method what I don't need to have some other return value: it's clean and simple.
Method 2: Create a global variable and store a handle of the object there. But this method sucks, because globals suck in general. I only mention it to tell you not to do it.
Method 3: Create a wrapper to hold a reference to the object. Then pass the wrapper to the "add" function, which can update the value within the class.
class SomeObjectWrapper
{
public SomeObject someObject;
}
...
void addItem(int firstnum, SomeObjectWrapper sow)
{
SomeObject o1=new SomeObject();
o1.firstnum=firstnum;
objectList.add(o1);
sow.someobject=o1;
}
...
void callingFunction()
{
SomeObjectWrapper sow=new SomeObjectWrapper();
SomeObject newObject=addItem(1, sow);
sow.someObject.secondnum=2;
... whatever ...
}
How about doing it with a return value:
RandomSubClass addItem(int firstNum)
{
RandomSubClass o1 = new RandomSubClass();
o1.firstNum = firstNum;
myListOfObjects.add(o1);
// Here I was thinking that 'toBeReturned' will get same address as
// 'o1', and by changing 'toBeReturned' (in main), values in 'o1' change
//
....
return o1
}
In Java all object are returned/passed via parameters by address. Only the primitives types (int, float, double...) are passed by value, if you want the primitive types to be passed by address use:
-Integer instead of int
-Double instead of double
-Float instead of Float
-ect...
I am making a copy of my object by using clone() method. But when there is modification in the copy the original object is also modified. I have tried to replicate my issue in the following example. Here are 2 classes ClassA and ClassB.
public class ClassB implements Cloneable
{
int num = 0;
byte[] bit = new byte[1];
//Getters and setters have been removed due to space constraint
public Object clone()
{
try
{
ClassB obj = (ClassB)super.clone();
obj.setNum(this.num);
obj.setBit(this.bit);
return obj;
} catch (CloneNotSupportedException e) {
return null; }
}
}
//Here is ClassA whioch contains the main method and uses clone
public class ClassA {
public void cloneMethod(){
ClassB objB = new ClassB();
objB.bit[0] = (byte)0x8;
objB.setNum(5);
ClassB objCopy = null;
objCopy = (ClassB) objB.clone();
if(objCopy.bit[0] != (byte)0x0)
{
objCopy.bit[0] = 0;
}
System.out.println(objB.bit[0]); //At this point the original object value is also modified.
}
public static void main(String args[])
{
ClassA a = new ClassA();
a.cloneMethod();
}
}
Now how to retain the original object value? I know clone has certain disadvantages. I have tried with new key word also but it doesnt help.Please suggest.
in my original code I have to use the original object bit value later for some more calculation and the copy object bit value will be 0.
Thanks.
Don't set bit to the same byte[] as the original object, instead clone it as well:
obj.bit = this.bit.clone();
Also, you don't need to set num, because that will already be set correctly on the object returned by super.clone().
obj.setNum(this.num);
obj.setBit(this.bit);
These two lines of code are (a) redundant and (b) wrong. If you just want the original field values in the clone you don't need this at all, because super.clone() has already done it for you. If your aim is to return an independently-valued object. As bit[] is an array, i.e. an Object, you should clone it too.
You are not cloning your bit array.