How does re instantiating work for this scenario? - java

I am using Java
public class MapsConfusion {
public static void main(String[] args) {
HashMap< Integer, ArrayList<String>> map = new HashMap<>();
for (int i = 0; i < 15; i++){
ArrayList<String> lst = new ArrayList<>();
lst.add("something");
lst.add("something2");
map.put(i, lst);
}
for(int j = 0; j < 11; j++){
System.out.println(map.get(j));
}
}
}
The way this works is, it creates a new arraylist each time it loops around. Here is my question,
Thinking about pointers, when you declare a new Arraylist<> each time, you are creating a new Arraylist at a new address am I correct?
Other question: Doesn't the list only exist within the scope, which is the for loop? Then how is isstill accessible when I do the other (last) for loop?

1 Question
Yes, you always create a new object and therefore a new address.
See this for further information: https://docs.oracle.com/javase/tutorial/java/javaOO/objectcreation.html
2 Question
The ArrayList exists as long as at least one variable pointing at it. In this case as long as map exists and the main method runs.
Here's more about the life cycle of an object: http://www.dummies.com/programming/java/the-life-cycle-of-a-java-object/

when you declare a new Arraylist<> each time, you are creating a new
Arraylist at a new address am I correct?
Yes you are right. Each ArrayListis created at a new memory location.
Doesn't the list only exist within the scope, which is the for loop?
Then how is is still accessible when I do the other (last) for loop?
It's accessible because each newly created ArrayList gets added in to your map and that's why you do not lose it when your first for loop ends.
If you do not add each newly created ArrayList in your map, you won't be able to access any ArrayList outside the first for-loop in which it is created.

Thinking about pointers, when you declare a new Arraylist<> each time,
you are creating a new Arraylist at a new address am I correct?
Correct.
Doesn't the list only exist within the scope, which is the for loop?
Then how is is still accessible when I do the other (last) for loop?
An object is automatically deallocated by the garbage collector only when there are no references pointing to it. In your case the list is added in map, therefore it is not deallocated since there is an element of map pointing to it.

Thinking about pointers, when you declare a new Arraylist<> each time,
you are creating a new Arraylist at a new address am I correct?
Yes you are correct the pointer to the List lst only exists in the scope of the first loop.
Other question: Doesn't the list only exist within the scope, which is
the for loop? Then how is isstill accessible when I do the other
(last) for loop?
But you assigned the object the pointer lst was pointing to, into the Map map outside the looop. Therefore the object still exists because the mapentry is pointing to it.
If you move the Map also into the first loop you will get a compile error.

Since you have not removed all references to the arrayList, it will still exist and remain accessible after the first for loop. The fundamental difference is:
the arrayList won't be accessible by any variable/pointers which you have declared within the for loop, as those variables are within the scope of the first for loop only.
During the run of the first for loop, you have pointed the hashmap's value entry to each individual list and apparently the hashmap is accessible beyond the scope of the for loop.
Converging from the above two points, all arrayLists are accessible from references made in HashMap's value

Related

Storing an Object into a temporary Object and not changing the original Objects value

I have an object stored in a global variable let's say:
static ArrayList<Object> list = new ArrayList<Object>();
I want to store it later to look into it without actually changing the values in the structure itself. So I am doing something similar to this:
public void someMethod()
{
ArrayList<Object> tempList = new ArrayList<Object>();
tempList = list;
list.remove(0);
}
I'm thinking this may have something to do with me initializing the variable as "static". I don't usually do that but Eclipse told me I had to so I just let the change happen.
My understanding would be that I am storing the original list into a temporary list and anything I do to the temporary list would be independent of the original list. But it appears that if I were to remove something from this above list, that the original list is removing it as well.
I remember learning that this could happen sometimes but I think I've done this before without having that issue.
I apologize if this is a repeated question but the way I worded it didn't show me an question that was similar.
Thanks!
My understanding would be that I am storing the original list into a temporary list and anything I do to the temporary list would be independent of the original list.
This is not the case. When you do something like
a = b;
then both a and b refer to the same object. Mutations in a show up in b and vice verse (since there is only a single object in question). In this case you probably want to use the copy constructor of ArrayList:
ArrayList<Object> tempList = new ArrayList<Object>(list);
Notice that here we are explicitly creating a new, independent object and assigning that to tempList.
Note that this creates what's called a shallow copy: the objects referenced by the list themselves are not copied, but instead a new list is created that contains the references to the same objects as the original list.
At the end of your someMethod, your tempList disappears into the dark void of the GC. If you want to keep it, you need to turn it into a similar field as list is.
Also, assigning list to tempList makes you have two references to the same object.

Objects lost in array

I am making a RPG-style program, but I have trouble to get my array of treasure objects to work. I want to save all treasures I find in the array, to be printed out later. Here is the code for the treasure class:
private static int x = 0;
Treasure treasureArray[] = new Treasure[20];
public void collectedTreasures(Treasure t){
treasureArray[x] = t;
x++;
}
And in the main program:
GoldTreasure t = new Coin();
hero1.setPoints(t.getCoin());
t.collectedTreasures(t);
The creation of the treasure object is within a switch within a infinite loop.
When i print out the array, with method
public void printTreasures(){
for (int y=0 ; y<x ; y++){
System.out.print(treasureArray[y] + ", ");
I only get "null" for as many treasures there should be in the array. If i print out the array after t.collectedTreasures(t), I see that only the last treasure is there, and the indexes before that object is null. What have I done wrong?
Yes I'm a newbie. Be nice.
This code is quite suspicious:
GoldTreasure t = new Coin();
hero1.setPoints(t.getCoin());
t.collectedTreasures(t);
It means you are:
creating a new treasure t;
calling collectedTreasures on that very instance.
You should assign the treasure array to the hero, not to the treasure itself.
Also note that x should not be a static variable because it will get shared among all instances; clearly not your intention, since the treasure array is per-instance.
The problem is that you collect the treasure in itself because you call the collect function - that belongs to a treasure - to collect itself.
Later on, when you call printTreasures in what object does it run? Do you create a new instance of treasure and ask for it to print what it has collected? If such, the results are according to the code and there is no issue with it, but the logic is faulty.
What you should do: the hero is the one collecting the treasures, therefore move the definition of the array of treasures, the counter and the 2 functions - collectedTreasures and printTreasures - in the hero class. Further more, make X not static, as its value will be shared among heroes. Maybe, even more ellegant, create an additional class to handle the treasures and compose you hero using different classes.
And may I suggest a renamig for the collectedTreasures(Treasure t) function to collectTreasure(Treasure t).
We would need to see your full code to give you a detailed answer, but I suspect what you are doing is creating lots of Treasure subclasses and calling collectedTreasure on each one. This is going to increment your global x counter each time, whereas each individual treasureArray only has one entry in it.
You can move the collectedTreasure method to the class corresponding to your hero1 object, at the same time, get rid of the static (global) x variable and replace your array of Treasure objects with a List implementation (e.g. ArrayList), they all keep track of their own sizes so you don't have to. Plus your code won't crash when you get more than 20 treasures!

Reference of two arrayList to same objects

I have this code. But I don't know how to explain the result:
ArrayList<String> first = new ArrayList<String>();
first.add("1");
first.add("2");
first.add("3");
ArrayList<String> second = new ArrayList<String>();
second = first;
System.out.println("before modified:"+second.size());
second.clear();
System.out.println("after modified:");
System.out.println(" First:"+first.size());
System.out.println(" Second:"+second.size());
The result will be: 3 / 0 /0
The problem I don't know is: when you assign first = second; so, both first and second array will point to same object (1,2 and 3). after you clear all elements on second array, so all reference between second array and these objects will loose (no problem here).
The thing I don't know is: but these objects (1,2 and 3) still hold reference to first array. Why first array's size is 0.
Please explain for me.
Thanks :)
By assigning second = first, there is only one arraylist with two references. The references are the same. So, when call clear using one of the two references (first or second), clear will be performed on the referenced arraylist.
This is something else than you first thought. It's not so that assigning the second = first all the references of the strings you added to the first one, will be copied into a new ArrayList object, that would be magic (in Java).
When you do first = second your ArrayList items will point to the same memory locations. Doing a .clear will remove the elements to which the ArrayList is pointing to. This will have repercussions on the other ArrayList.
If you just want to copy the elements of ArrayList1 to ArrayList2, you could do something like so: ArrayList<String> second = new ArrayList<String>(first);
but these objects (1,2 and 3) still hold reference to first array.
Why first array's size is 0.
ArrayList<String> second = new ArrayList<String>();
second = first;
is the same as writing
ArrayList<String> second = first;
You have made second reference point to the first arraylist,it is not using a new arraylist. So when you call clear it clears the "first" arraylist created - you have two references pointing to one arraylist.
When you assign one ArrayList to two variable and modify any one of them, this will reflect in both.So operation performed in any of one variable also reflect in second one. (Single object referenced by two variable).
In Java a variable (except primitives) is always a reference (which has the start address of object) to an object only, Reference is never an object in itself.
For example
second = first;
is assigning a reference, so that first and second now refering to the same object. Objects are not copied, neither in assignments, nor in argument passing (what is copied/assigned is the reference).

Multimapping and anonymous values

I wish to create an instance of TreeMap whose keys will be of type String and values of
type ArrayList <String>:
Map<String, List<String>> directory = new TreeMap<String, List<String>>();
String[] names = {"Anne","Ben","Charles","Dawn","Edward"};
for (int i = 0; i < names.length; i++) {
directory.put(names[i], new ArrayList<String>());
}
My question here relates to line 5 of the following code. Is it acceptable/best practice to pass an anonymous object (in this case given by new ArrayList()) as the actual argument to the put() method? My rationale for this is that by the nature of a map, these objects can still be reached by the following for example:
directory.get("Anne");
I don't see anything wrong with that. As a matter of fact, I don't even see a reason to call such a thing "anonymous". You are simply avoiding declaring a variable (i.e. a reference to that object - you are still creating the object) that you are never going to use anyway.
There is no such thing as an "anonymous" object in Java. There are anonymous classes, i.e. classes that don't have a name. An object has no concept of a "name". It is simple referred to by one or more references as needed.
Nothing wrong with that at all. I use it all the time.
In your code you create a new ArrayList object for every one of those names. Is this what you wanted to do? Whether it is best practice depends on what you are trying to do, it would be best practice to store e.g. the names of the pets these people own (a list of pets for every person).

how jvm handles creating object inside a loop

List list = new ArrayList();
String[] test = {"ram", "mohan", "anil", "mukesh", "mittal"};
for(int i =0; i < test.length; i++)
{
A a = new A();
a.setName(test[i]);
list.add(a);
}
How JVM handles creation of object a in each loop? How "list" differntiate between different instance? Is it good practice to create object on each iteration. If no, what is the best solution for adding object into a list.
In your example a new object is created on each iteration of the loop. The list is able to differentiate between them because it does not care that you call them all "a" in your code, it keeps track of them by the reference that gets reassigned each time you call
a = new A();
Each time that line of code is called, a new object is created on the heap and it's address in memory is assigned to the reference a. It's that reference that the list keeps a record of, not the variable name.
This is a perfectly fine and normal way to populate a list (aside from the syntax errors that others have mentioned, which I'm assuming you can fix when you try to compile your code).
List holds a reference to each instance of a that gets created. It's fine to create each object inside the loop (I'm assuming you mean as opposed to declaring the 'a' variable outside the loop and then re-assigning it each iteration).
Is it good practice to create a new object on each iteration?
One of my friends told me that it is not a good practice to creating so much instances.
If you need different individual instances, you need to create them.
Since your list needs five objects with different names each (ram, mohan, anil and so on), you need a new object for every iteration of the loop. How else are you going to store the five names?
As for declaring the variable a outside of the loop, I do not think that makes a difference performance-wise and also reduces legibility.
A a; // dont do this
for(int i =0; i < test.length; i++){
a = new A();
a.setName(test[i]);
list.add(a);
}
You might be interested in the for-each loop
for(String name: test){
A a = new A();
a.setName(name);
list.add(a);
}
If my understanding of the JVM is correct, the posted code will have no performance difference compared to
for (String name : test )
{
list.add(new A(name));
}
(assuming, of course, that the constructor A(String s) is another way to create a new instance with a specific name)

Categories