Java collections and memory use - java

I have a question on Java memory use. It’s for my edification and anyone else who searches and finds this later! For the purpose of the question, please assume, this is a single method and nothing goes out of scope... during my question ;-)
I have created 5 new objects with a single property called ‘name’ of type String.
I create an ArrayList and add the 5 objects to the ArrayList. I then create a HashMap and iterate through the previously created ArrayList, adding the objects to the HashMap.
Q1. When I add the objects from the ArrayList, to the HashMap, I assume I am just creating another collection of ‘pointers’, since I’m not using the ‘new’ keyword. Therefore no new memory is consumed, except for the HashMap itself (the objects are not duplicated).
Q2. If I change the value of ‘name’, in an object in the HashMap, would the same change be seen, if I were to iterate over the ArrayList, after making the change.
I appreciate a ‘sanity check’ on my understanding.

Q1: The HashMap is created and the references to the objects are created. So memory is consumed, but references aren't terribly big, but can make a difference if the number of references is huge.
Q2: Edit: Yes, the name field would change. Better still, write a small program to check it out.

A1 : Yes, other than the references and HashMap, nothing new will be created. (Assuming you are not creating a new set of keys for for the HashMap)
A2 : Yes, the change will reflect on the ArrayList.

To answer your questions.
1.) When you add objects to a HashMap the objects are not duplicated. Internally though the map will create new objects to maintain its inner structure. The inner structure of a map consists of HashMap.Entry objects that contain a linked list with all values that map to the same hash code. Thus whenever you add objects to a map one or more internal objects are created.
2.) I assume you stored the objects in the HashMap using their name as key. In this case chaning the name of an object will update the object (no matter whether it's being accessed through the list or the map, it's always the same object) but not the mapping in the map. In the map the object will still be store under its old name!
Map map = new HashMap();
Foo f = new Foo();
f.setName("A");
map.put(f.getName(),f);
f.getName(); // => "A"
map.get("A"); // => f
f.setName("B");
f.getName(); // => "B"
map.get("B"); // => null
map.get("A"); // => f

Related

How to create a generic number of objects?

I am currently thinking about how to create n objects of type x in Java.
Thought experiment: You want to create all entries from a specific database table as an object.
The number of entries are given by counting them.
The object to be created is a model of a table entry.
My current strategy would be to create Lists foreach column.
After that, I would create an Object by looping through the Lists, append it to a HashSet and continue with the next row.
But probably there is a problem with the references, because the created objects would have the same name and if I remember right, I would overwrite the pointer by creating another object in this case. So it's the question if the HashSet still contains the old reference or not.
Besides this solution would be very ineffective cause of the number of loops.
Pseudocode
HashSet for objects
lists of every column
iterate through lists
create object with values at position i of loop
append object to HashSet
If you have a clue about to solve the pointer problem or if it does not exist, I would be glad about your answer. Moreover, I would be grateful for more suited solutions.
PS: I did not found any design pattern for this use case
If I'm correctly understanding the "pointer problem" to which you refer, it does not exist. I think you may have some misconceptions about how references, as they are properly called in Java, work.
Take the following code
Set<MyObject> mySet = new HashSet<>();
MyObject myOb;
myOb = new MyObject("Object #1"); // 1
mySet.add(myOb); // 2
myOb = new MyObject("Object #2"); // 3
mySet.add(myOb); // 4
At the lines marked // 1 and // 2 we create a MyObject object with the data "Object #" and add it into a Set; the variable myOb references the object we've just created.
If we were to print the contents of the set at this point, we'd see
{["Object #1"]}
At line // 3, we create another new MyObject object, this time with the data "Object #2", and assign myOb to reference it.
But wait! We've just added myOb (which was referencing an object with the data "Object #1") to the set, and now we're changing myOb to reference a different object. Does that mean our set suddenly looks like:
{["Object 2"]}
No, it doesn't, because what was added to the set was not myOb itself, but the rather the myObject object that myOb happened to be referencing at the moment that mySet.add(myOb) was called. All the set received was a reference to a MyObject instance; it hasn't the slightest clue that the reference happened to be stored in the variable myOb.
Thus we can make myOb reference (or "point to", if you prefer) any other MyObject object (or even the same object again) without affecting the set in the slightest.

Object reference clarifcation

Please correct me if I am wrong, I just want some clarification that I'm understanding this right.
When you create an object in java you use the new keyword followed by the class type. Ex. new [someclassnamehere]();
Depending on your constructors you can pass arguments by supplying them in the parameter when you create the object.
I'm not sure if it would ever be useful to just have a line of code that creates a new object o by just using the new keyword, because nothing is actually holding the reference to that information. But it's correct it seems.
So you can create a variable that contains the reference to the new object you are creating by using type name.Such as: Employee someData; . But it has yet to actually reference an object, seeing as one hasn't been created yet. So by applying the above information discussed:
Employee someData = new Employee(name);
We now created an Employee object that contains some name of the employee. The new keyword created an instance of the class Employee, an object, in which the someData variable references that newly created object.
So now the someData variable can be said to reference the Employee object because it contains the address in memory of where the object is stored. This address will allow us to access the actual data of the object, in this case the name of the employee.
If I were to create an ArrayList that has the datatype Employee, I can store Employee objects in it. So I can add the someData variable to the arrayList as well as someData2,someData3,etc. (Just assuming they are all of the same type but contain different employee information).
So each of those variables contain references to these objects. The ArrayList object then contains references to these objects as well because the ArrayList elements contain these someData variables which reference the Employee Objects.
example:
ArrayList.get(1) -> someData -> reference variable(address) -> employee Object
ArrayList.get(2) -> someData2 -> reference variable(address) -> employee Object2
Pretty sure I got the idea down so far, but what slightly throws me off is when you actually don't create a reference variable.
So let's say you create a loop which creates an object(data is being read from some database,etc) and adds it to an ArrayList. In this loop you collect the data you want and use that to create an object, which is then directly added to an ArrayList.
Let's say it looks like this (combination of some pseudo code and actual code)
ArrayList<Employee> list = new ArrayList<Employee>();
// While data from the database still exist (while loop,etc)
// extract some sort of data from the database, such as their name and hours
// create an object of this information and store it in an ArrayList
list.add(new Employee(name, hours);
// end loop
For simplicity, let's said the loop ran 5 times so it created 5 objects.
This means it added 5 objects to the ArrayList List and the references to these objects are actually contained in the ArrayList elements. So to get the first object added to the ArrayList you would use list.get(1) (I'm pretty sure ArrayList start at 1 and not 0 for indexes), which returns the reference to that object.
EDIT: Please forgive me for my mistake here, I suppose I had a brainfart and got mixed up. I don't know why I thought ArrayList indexes worked like that for a second
Is this correct and standard way of creating objects through the use of a loop?
I'm not sure if it would ever be useful to just have a line of code that creates a new object o by just using the new keyword, because nothing is actually holding the reference to that information. But it's correct it seems.
Imagine that the constructor starts a new thread. No reference, but
new AmazingThread();
is fine in that case.
Well, this question is huge. And yes, creating objects like this is completely legit. You can think of ArrayList having it's own variable storing the reference.

ArrayList constructor accepting Collection

I have a simple question.
Lets say we have a Map, for example a Map<String, Object>
I want a method that returns a list of all values inside the Map.
The approach i use is the following:
I create a List<Object> myList = new ArrayList<>();
Get an iterator from the value set of the Map.
For each element inside the iterator i put a reference in the myList list.
Return the list
...later for each element i use i wrap it inside a synchronized block because the list contains references.
Now i am woring about using an easier apporach. The one i mean is the following:
return new ArrayList(myMap.values());
As you see in this case i simply use the constructor of the List interface which accepts a Collection.
And finally my question is:
If i use the second approach do i still get references or it copies the value objects that are inside the map?
In both cases you will get "shallow" copy of collecion, so both arrays will keep references to the same objects.
return new ArrayList(myMap.values()) will return an ArrayList containing the references of the original values of the Map. No copies of the values instances are created.
Note that if your Map contains duplicate values (i.e. values that are equal to each other), your ArrayList will also contain duplicate values. If you want to eliminate the duplicates, you should create a Set of the values instead of a List.
In either case you'll get a copy of the reference (so called "shallow copy").
There is no deep-copying (creating a completely new object with meaningfully equivalent fields -- also deep-copied) involved.

Multiple keys pointing/refering to same Object in values in HashMap

I have a HashMap , which has a Object (with 2 String objects as member variables of it) and value as Object containing 3 different Strings.
Say:
Map<ReqDTO , RespDTO> map = new HashMap<ReqDTO ,RespDTO> ();
suppose I have following values :
KEY VALUE
1 ("str1","1") - ("1","2","3")
2 ("str2","2") - ("a","b","c")
3 ("str3","3") - ("1","2","3")
4 ("str4","4") - ("v","b","g")
5 ("str5","5") - ("1","2","3")
When I have thousands of such records , (which is Cache in my application) , then VALUE part of record number : 1,3,5 is holding memory of 3 objects. I want to make KEYS of 1,3,5 records to point to same instance of the VALUES (1,2,3 , in this case) and not as separate memory.
Is there any variant in HashMap for the same? or Any other Datastructure will do..
NOTE: It is loaded only once and all the operations performed on this are READ only..
What should be the preference of datastructure to make it performance intensive ,In other words, It can have costly insertion.
You could use a technique called interning, which is essentially mapping all objects that are equal() to each other to a single authorative instance.
That's used in Java for Strings using String.intern().
But there are some drawbacks to using this method ('though they have been reduced quite a lot with modern JVMs). As an alternative you can use the Guava interface Interner.
Just create a single Interner using the Interners helper class:
Interner strInterner = Interners.newStrongInterner();
and pass each String value through the interner before using it in a key or value:
String v1 = strInterner.intern(param1);
This way for any given value, you'll only ever use 1 String instance. The same can be done for any other class (as long as it correctly implements equals() and is immutable).
You can even discard the Interner after you've constructed the map.
Well, if you put the same object into the map for both keys, then they'll both be the same object. If you have different instances of the object that are .equals() to each other, it gets more interesting. You could try using Flyweight for your value objects, or you could walk through the values() of the map - if you find an equals() value object, put your key with that object instead of the one passed in.
Someone, somewhere has probably already written a Map implementation that does what you want, but my best recommendation there is to use Google and hope they're good at SEO.

How to retrieve a specific object from an array of objects in java

I have an very large array of objects where objects are constantly added and every object is dynamic and contains different parameters that define it (getParam1() etc..).
I need a data type that allows me to point directly to an object in the array that contains a specific parameter without having to index through the entire array every time that I require a specific object.
Does any datatype provide this functionality in java or would I have to create my own? And in that case how would I do this?
Thanks.
You could maintain one map per parameter and update each one when the parameter changes. If you don't have control over either the mutating, or the mutable class, then there's not much else you can do other than linearly search through your objects.
I have an very large array of objects where objects are constantly added and every object is dynamic and contains different parameters that define it (getParam1() etc..).
An array is an static structure. If you're going to constantly add elements to it you should reconsider using a dynamic collection such as a List, a Set or a Map. If you're not modifying the length of the array and you're just updating the different objects on it, you're ok. Still, you are going to have to keep track (an index, amount of objects, etc.) of the array's current status, because you will need to know where to put your objects.
I need a data type that allows me to point directly to an object in the array that contains a specific parameter without having to index through the entire array every time that I require a specific object.
This will require some middle logic one way or another. If you point to an object that has certain parameter what happens if more than one object has it? You have to define which one is the correct one. On the other hand, if you point to the parameter you still need to know the related object.
I'd say that rather than using an array you should try with a Map with entries where the key is the parameter and the value is a Set, containing the different objects related to that parameter.
A Map is sufficient if you only map a parameter to one object, but I'll cover a more complex situation, just in case.
Please note that an object can be present in multiple Sets, because two parameters would require for it to be mapped twice to allow it to be found.
I've looked into maps but it's not really ideal when it comes to my objects.
I don't know your current context and how do you identify your objects. Should you have an ID or any sort of unique identity assertion, you can turn the Map of Sets to a Map or Maps where you can obtain a Map containing objects associated to a certain function and then obtain a particular object through that ID.
Finally, if nothing suffices, you should create a structure that covers your needs. Still, for instant access, you're better off using a Map or a really well-oiled array.
Use a Map instead of an array:
Map<String, MyObject> map = new HashMap<String, MyObject>();
MyObject o;
String someId = o.getId(); // use some identifying id for your objec
map.put(someid, o); // do this for all your objects
then when you need to retrieve one:
MyObject o = map.get(someId);
If you need all the objects (possible, but unlikely):
List<MyObject> objects = map.getValues();

Categories

Resources