What happens if two objects of the same type have identical reference?
For eg -
BufferedReader bufferedReader=null;
try{
bufferedReader = new BufferedReader(new InputStreamReader(a.openStream()));
while ((inputLine = bufferedReader.readLine()) != null) {
//do something
}
bufferedReader = new BufferedReader(new InputStreamReader(b.openStream()));
while ((inputLine = bufferedReader.readLine()) != null) {
//do something
}
}
a and b in this case are URLs.
The code I have here is similar to this page. In this case, will the buffered reader object first have the data of URL a, and later the data of b?
I don't believe that you've phrased your question to mean what you really want to ask. To answer your unasked question ...
You have a reference bufferedReader of type BufferedReader.
On line 1, you initialise the reference to null. It doesn't point to an object.
On line 4, you change where the bufferedReader reference points to. It now points to an object that ultimately sources data from a.
One line 7 you change where the bufferedReader reference points to. It now points to an object that ultimately sources data from b.
will the buffered reader object first have the data of URL a, and later the data of b?
Yes, your code will retrieve the data from URL a, and then retrieve the data from URL b.
What happens if two objects of the same type have identical reference?
That would be more like:
Foo o1 = new Foo();
Foo o2 = o1;
Now, o1 and o2 point to the same object. In that case, invoking a method via either reference will affect the same (single) object.
It is nothing but similar of doing,
Let me explain giving simple example, you will be able to map then in your case.
int a = 10;
a = 2 + 3 ;
sysout(a);
// a have 5 right now, next line will change the contents to 9,
so previous data within a is no longer exist.
a = 4 + 5 ;
sysout(a);
User defined type
class Student{
private int rollNo;
//getter-setter
}
Student s = new Student();
s.setRollNo(10);
sysout(s.getRollNo);
Now, on same reference you are creating object for new Student, then reference to previous Student will be lost and your reference will start pointing to new Student Object.
s = new Student();
s.setRollNo(20);
sysout(s.getRollNo);
The same variable (bufferedReader) refers to one object after the first "new", then it's reassigned to a second, different object at the second "new".
It's also worth noting that the Java garbage collector will free unused objects ... but it WON'T close files that are still opened. The second "new" introduced a resource leak ;)
Well think about it this way - each time you're calling the new keyword, you're calling the constructor of the object class after it. And that creates a new object for you on the heap. So in the snippet above, you've done that twice, first you initialize a BufferedReader() object chained to stream a, for your bufferedReader reference. Once the while loop completes and you hit the next new keyword, you create another BufferedReader object chained to stream b, and now your bufferedReader reference handle points to that.
Java has automatic garbage collection, and one reference can only point to one object on the heap at a time (even an Array is considered its own object). So once you switch the reference from the BufferedReader object chained to a, to the one chained to b, the former one is garbage collected.
Remember that on the left side is declaration, e.g.:
Object obj1;
The right side is a call to create a new object of the provided type, e.g.:
obj1 = new Object();
The equals in between makes your obj1 reference point to that newly created object on the heap. Hope that helps.
Related
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 7 years ago.
I have a list of Cell object that represent a board game inside the board class.
Cell boardGame[][] = new Cell[8][8];
I needed a temporary cell to try the player move on him and compare it to the other cells, so I though that I could use a java pass-by-value to do it.
test(board.boardGame);
board.printBoard();
private static void test(Cell[][] boardGame) {
Cell c = new Cell((new Soldier(ChessPiece.QUEEN, Color.WHITE)), 7, 4);
boardGame[7][7] = c;
}
I read some post about java here, but apparently I still didn't catch it 100%.
I expected to see only one white queen on the board, but I saw two.
I know that if you pass a reference you can change its values, but I though that if I would pass the array itself its members won't be modified unless I would execute a return.
Please help me to understand this subject better.
Thanks
Edit:
I think I don't understand when it called attributes and where it doesn't.
I though the different it if you are call "new" or not.
When its part of another object it called attribute right? but every object can be created as part of another object. I can create a new string in dog class and then create the dog class in the animal class and then create it in another class. So only the top class is in the stack?
For exemple:
public class Board { //fake class
int num= 0;
public void test(int i){
i = 1;
}
}
and on another class:
public class Main {
static void outsideTest(Board board){
board.num = 1;
}
public static void main(String[] args) {
Board board = new Board();
System.out.println(board.num);
board.test(board.num);
System.out.println(board.num);
outsideTest(board);
System.out.println(board.num);
}
}
Now I didn't understand why on test() method the num didn't change and on outsideTest() the num change, num as been created in the heap because its part of the board object, so its need to be changed on both cases no?
The best and least confusing way to remember it is as follows: Java passes everything by value, that includes the references. :)
When you have a variable:
Object a = new Object();
you don't actually have an object stored in a. What you have is a reference to an object somewhere in memory.
Likewise when you call a method on an object:
String b = a.toString();
you don't do that. What you call is a method that uses the data of the referenced object as its context.
So when you pass an object as an argument
System.out.println(b);
You don't pass the whole object. You pass the reference and that reference is passed by value.
edit:
If the reference were not passed by value, but by reference, you could do something like this, which fortunately you can't.
public void swap(Object a, Object b){
Object swap = a; a = b ; b = swap;
}
String a = "a";
String b = "b";
swap(a,b);
// would print "b a" if references were
// passed by reference but instead prints
// "a b" as they're passed by value.
System.out.println(a + " " b);
The reference to the object is passed by value, which means that
boardGame = new Cell[8][8];
does not do any harm, but changing anything you get from boardGame does.
Java is essentially always "pass-by-value".
Caveat: It passes the value stored in the memory for the variable.
For primitive data types, the memory is allocated in stack space, whereas for objects reference memory is allocated in stack space but the object itself is created in heap. Similar can be stated for arrays too though they are not exactly objects in a strong sense.
Diagrams below would make it clearer.
Your Cell object 2D array should seem something like anObjectArrayVar (not exactly as the ref in the diagram pointing to the objects should now be pointing to the rows and we would need another level of allocation in heap in between ref and objects for each row (a set of cells refering to the objects).
So, when you pass boardGame, the value stored in the stack is passed that stores the reference to the array of objects (just like the value stored in the anObjectArrayVar). If say the list of refs is stored in location numbered 50 then anObjectArrayVar would have stored that and it passes that value to the test method when we call it. In such a scenario the test method wont be able to goto memory location anObjectArrayVar and change its value (to say 100) as it has only a copy of the value but it could easily change what it refers to(directly or indirectly) like the values in ref or the next level (and add new objects as in your case adding a new cell with queen) or the objects pointed to by them and those changes would reflect through out the program!
I would also like to draw your attention to the fact that the code
boardGame[7][7] = c;
would replace the current cell (as well as the soldier currently in it) which would create major issues if there was originally a soldier in that place at that point in the game. The game state would actually change.
As a suggestion (given the limited knowledge about your design) I would say at least save the cell in some other value in test method before replacing it.
Cell old = boardGame[7][7];
//now do all your operations
boardGame[7][7] = old;//just before returning from the function
I have read it everywhere that Java stores Object references in array. Even i demonstrated it myself.
But then i changed the state of the object, means i changed the values of attributes and saved in array, and i can retrieve multiple state of same object. If Array saves only references then how do references holds the states.
For example:
class Test{
String id;
}
Test[] testArr = new Test[2];
test = new Test();
test.id = "ABC"
testArr.add(test)
test.id = "XYZ"
testArr.add(test)
now in case above if we would storing only references then second assignment would have overwritten id value of test object and both entry in array would have same value of id, but this is not the case and we can retrieve the id values ABC and XYZ. I am confused!
Take a look at this code:
class Test {
String id = "A";
}
public class Main {
public static void main(String[] args) {
ArrayList<Test> list = new ArrayList<Test>();
// Adding some Test Object to the list.
Test foo = new Test();
list.add(foo);
System.out.println("Value of foo id: " + foo.id);
// Retrieving the Object from the list & changing the value
Test bar = list.get(0);
bar.id = "B";
System.out.println("Value of foo id: " + foo.id);
}
}
output:
Value of foo id: A
Value of foo id: B
As you can see the arraylist only holds references. If you retrieve the Object from the list and change something in it, the original Object will be changed too
To answer your question. Yes. All variables are simply references to the location of an object, not just an ArrayList. Writing MyObject obj = new MyObject(); creates a new object however the variable obj is just a reference to the location of that object in the Heap (aka memory).
An ArrayList (without looking at its actual implementation) simply stores each reference to the location of an object as an index of the ArrayList rather than a unique variable.
In a bit more detail: You need to understand what each part of creating an object does. Try to imagine it in this way:
Each object is located in a memory address that takes up the number of bytes all its fields use. Lets imagine we have an object called MyObject that takes up 100 bytes. When we create an Object using the new keyword (ie. new MyObject()) it is stored in a memory location in the heap (which is an area of memory set aside for your program to use as dynamic memory allocation). Let us say that when this object is created it takes up memory space 1000 (up to 1100 because it uses 100 bytes of memory). So:
|MyObject| <-- this is a visualization of memory space
1000
The when we write MyObject obj it sets aside memory in the stack (which is used for static memory allocation) and this will hold the location of the object. So it may hold the reference to the location of the object in its own location which we will pretend is labeled 4
|______| <- empty memory location because it hasn't been assigned yet.
4
When we put the 2 instruction together and write MyObject obj = new MyObject() it puts the address of the object into the memory location of the variable so we end up with:
|MyObject| <-- location of actual object
1000
|1000| <-- location of variable which a reference to the location of the object
4
I have never seen the keyword "new" used in a return statement and my understanding of new is that it creates a new object. And "new" used in this context Practice permutation = new Practice(); is that it creates a new object called permutation. And permutation is a reference to some memory address. So maybe, return new String(content) is return a memory address? So my question is, what does new used in this context actually mean? I apologize for my noob question...
import java.util.Arrays;
public class Practice {
public String sort(String s) {
char[] content = s.toCharArray();
Arrays.sort(content);
return new String(content);
}
public static void main(String[] args){
Practice permutation = new Practice();
System.out.println(permutation.sort("hello"));
}
}
return new String(content); means it creates a new string object with the content you have passed. It's similar to
String str = new String(content)
return str;
When using the keyword new you shouldn't associate it with any assignment operator. What the new keyword does, in laymans terms, is it creates a reference to a new instance of the specified class and returns it. So when you put the statement
new Object();
That statement is completely valid and it is returning a new reference to an Object class. The only thing is that the reference doesn't get set to anything because there is no operator performing on it. So when you have
Object myObj = new Object();
The reference comes from the new Object() statement and the equals operator sets it equal to the myObj variable. So now, if you understand that, when you have
return new Object();
The reference comes from the new Object() statement again and the return keyword takes that reference and returns it out of the method that you're in.
Your theory is correct, but your understanding of variables is a little off (in a very common way...) An object never has a name; it exists independently of any variables referring to it1. Practice permutation = new Practice(); does three things:
It creates a new Practice object
It creates a new variable that may refer to a Practice object
It makes the variable actually refer to the new object
Note that permutation is not the name of the object; it is the name of the variable, and the variable refers to the object. You can create several variables that refer to the same object, and you can create an object that is not referred to by anything - and the latter is what happens in return new.
1Whether there are any references to an object actually does have an effect, as an unreferenced object may be garbage collected - but that is a more advanced topic.
This:
return new String(content);
Is (logically) identical to this:
String result = new String(content);
return result;
It just skips the step of storing the value in a variable and returns it directly. There's nothing different happening, a new object is being instantiated and an object is being returned.
return new String(content);
does 3 things:
1) In creates String object somewhere in memory
2) In creates pointer (or reference) to it in this stack of you current thread
3) It returns this reference to the caller.
The same as
s = new String(content);
return s;
Both ArrayList and Integer are object data type, but why the code below treats the two differently?
ar,br,a and b are all objects.
Changing ar changes br, but changing a did not change b why? Isn't it both ArrayLists and Integers are objects? assignign an object to another object by using = statement simply does the shallow copy FOR BOTH? or no?
import java.util.ArrayList;
import java.util.Arrays;
public class MyClass {
public static void main(String[] args) {
ArrayList <Integer> ar = new ArrayList<>(Arrays.asList(1,2,3));
ArrayList<Integer> br = ar;
System.out.println(Arrays.toString(br.toArray()));// [1,2,3]
ar.remove(0);// lets change ar
// now lets see if br changed too
System.out.println(Arrays.toString(br.toArray()));// [2,3] (yes did)
Integer a= new Integer (5);
Integer b = a;
a = a+1;// lets change a and see if b changed too
System.out.println(b);// b is still 5
//So changing ar changed br too, but changing a did not change b why? Ist it both br and b are objects?
}
}
This is because Integer objects are actually boxed primitives. When you call Integer a= new Integer (5);, you create a new Integer. When you execute Integer b = a;, then b refers to the same instance of Integer as a.
When you call a = a+1;, the following happens:
a is unboxed into a primitive int with value 5.
The result of adding one to that int is evaluated.
The result, 6, is boxed into a new Integer that has a value of 6. The original integer of value 5 is not modified.
In the case of the list, you are assigning both ar and br to refer to the same instance of java.util.ArrayList. Modifications to that arraylist are seen when you access it through both ar and br.
The critical point is that a = a+1 constructs a new java.lang.Integer() through unboxing, evaluation, and boxing, while ar.remove(0); affects that list without creating a new copy of it.
More JLS reading:
If p is a value of type int, then boxing conversion converts p into a reference r of class and type Integer, such that r.intValue() == p
You need to understand the difference between variables, reference values (and dereferencing for field access and method invocation), and objects.
A variable is just a holder for a value.
A reference value is a value which is interpreted as the location of an object.
An object is ... an object. It has accessible fields and invocable methods.
Here
ArrayList <Integer> ar = new ArrayList<>(Arrays.asList(1,2,3));
ArrayList<Integer> br = ar;
You create two variables which store a single reference value which points to the single instance created with new ArrayList<>(..). So both variables are referencing the same object.
When you invoke a method by using a method invocation expression
ar.remove(..);
the JVM uses the reference value to find the object and invokes its method. This is the same object referenced by br. So when you then do
br.toArray()
you're still accessing the same object.
Here
Integer a = new Integer (5);
Integer b = a;
you create two variables that are referencing the same object.
Then you do
a = a+1;// lets change a and see if b changed too
which assigns (=) a new reference value to the variable a. So now a references a different object than b.
So:
ArrayList <Integer> ar = new ArrayList<>(Arrays.asList(1,2,3));
ArrayList<Integer> br = ar;
System.out.println(Arrays.toString(br.toArray()));// [1,2,3]
ar and br are the same instance
ar.remove(0);// lets change ar
// now lets see if br changed too
System.out.println(Arrays.toString(br.toArray()));// [2,3] (yes did)
The content of ar is changed. Since ar == br, the change can be seen in br.
Integer a = new Integer (5);
Integer b = a;
a is a new object, and again b is assigned to be the same instance
a = a+1; // lets change a and see if b changed too
System.out.println(b); // b is still 5
The reference of a is changed. a now points to a newly created object. b still points to the first created object.
this was just asked, earlier today, the Integer b is immutable and wont change, but the arraylist is just a reference...
I wish to confirm which scenario will cause a Garbage Collection on the object myObj:
Scenario 1
ArrayList arList = new ArrayList();
while(someCondition)
{
myObj = new MyObect(); // a custom object
arList.add(myObj);
}
Scenario 2
ArrayList arList = new ArrayList();
while(someCondition)
{
myObj = new MyObect(); // a custom object
arList.add(myObj);
myObj=null;
}
Does explicitly setting an object as null improves garbage collection behavior or will be it same when I reset the object using the new constructor ?
You don't specify the scope of myObj and its important. If its a local variable it almost certainly doesn't matter. If its an instance variable then that could be a long-lived and unnecessary reference in which case setting to null will be useful.
Update: given the updated information that myObj is local to the method, it will be of zero value to set it to null at the end of each iteration of the loop. Consider this example:
public void process(String text) {
String[] lines = text.split("\n");
List<MyObject> list = new ArrayList<MyObject>();
Object myObj;
for (String line : lines) {
myObj = new MyObject(line);
list.add(myObj);
// 1. set myObj = null here
}
list = null; // 2
// 3. do some other stuff
}
public class MyObject {
private final String line;
public MyObject(String line) {
this.line = line;
}
}
Now in this example, let's say that at step 3, it took a long time. Say 10 minutes. During that 10 minutes myObj is pointing to the last line processed. Doesn't sound like a problem? Well it could be. The way substrings work in Java is that they reference the original string. So if you do:
String s = ... // 100 megabytes
String s2 = s.substring(100, 101);
you're actually keeping the entire 100MB in memory because s2 references s.
So in the function I have above, myObj references a line which references the entire file. Changing step 1 to myObj = null; would actually help that because this reference is preventing the object being garbage collected.
Note: step 2 is important here because if you didn't nullify the list all the references would exist anyway.
You just need to think about how references work. An object won't be garbage collected while a reference to it exists. This means clearing long-lived references and keeping variables scoped as tightly as possible. The correct solution for the above is:
for (String line : lines) {
Object myObj = new MyObject(line);
...
}
and then myObj is scoped inside the loop so as soon as the loop ends or another iteration begins it has gone out of scope, which is much better.
Setting it to null will have no effect, since the object is still reachable via arList.
That is, your MyObect instances will live at least as long as arList.
EDIT: Based on your comment, it does sound like myObj is longer-lived. In that case, set it to null after the end of your loop.
I think that this is the root of your misunderstanding.
hmm.. but I don't wish to keep 2 copies of myObj , one in arList and one in the original variable. How can I flush myObj once I add it to arLsit ?
You do NOT "keep two copies of myObj". In your examples, there is only ever one "copy" of each MyObject instance created by the loop. The sequence is:
You create a MyObject instance, assigning its reference to myObj.
You add the reference to the instance to the ArrayList that arList refers to.
You assign null to the reference in myObj.
Note that adding the reference to the list does NOT create a copy of the MyObject instance. It simply means that that you have the reference in two places instead of
one. And when you assign the null you once again have the reference in just one place.
The other thing to note is that assigning null to something will never CAUSE the garbage collector to run. All it does is to (explicitly) remove a potential copy of a reference from consideration the next time the garbage collector is run.
Finally, if we assume that the scoping is as follows, then the line C will have no discernible effect ... unless either line A or line B triggers a garbage collection.
{
MyObject myObj;
ArrayList arList = new ArrayList();
while (someCondition) { // A
myObj = new MyObect(); // B
arList.add(myObj);
myObj = null; // C
}
}
Because it is in a while, myObj is always overwritten (the reference). So in Scenario 1 only one object (the last added in arList) will not be null.
It would be better if you declare it in the while statement:
while(someCondition)
{
MyObect myObj = new MyObect(); // a custom object
arList.add(myObj);
}