I have the code:
private class Record {
byte year;
float val;
}
Record record=new Record();
List<Record> recList = new ArrayList<Record>();
...
//now I add first element to array list
record.year=12;
record.val=55;
recList.add(record);
//now I add second element to array list
record.year=13;
record.val=77;
recList.add(record);
As you see I add different elements.
But as a result all elements in array list are the same.
So adding 2-nd, 3-d... element changes all previous elements
to the values of last "record".
What's wrong? Thanks?
An ArrayList keeps a list of references to objects. You're always modifying the same original object which means the reference is the same, but its values differ.
You can fix it by explicitly assigning a new instance to the record variable:
record.year=12;
record.val=55;
recList.add(record);
record = new Record();
record.year=13;
record.val=77;
recList.add(record);
You need to instantiate new objects so they are physically different objects. Right now, you only have one object that is in the ArrayList multiple times.
Record record = new Record();
Also, you should add hashCode() and equals() to Record since you are working with collections.
As you see I add different elements
No, you just edited old Record object and added it again. Each time before you add Record object you need to crate new one.
Related
I have a problem with Java: I have a list of integer that I want to put into a specific column and line of an array. For example, in column 1 I want to put [1,2,3] and column 2 [8]...
I tried something - I wanted to put the list into the array and then clear the list to put new values and put in another location of my array etc...
I created an array (RANG) of list and my list (ELEMENTS):
List[] rang=new List[nbSommets];
List<Integer> elements= new ArrayList<>(nbSommets);
I added some numbers and I put into the array ALL my list
rang[???]=elements;
Then, I clear the list to put new values
elements.clear();
But when I clear the list, this clear the list into my array too...
How can I do it ?
Thank you !
When you do rang[???] = elements; you are only assigning a reference to the array elements to rang[???], you are no copying all the values in a new array.
What you have to do is, instead of clearing the elements array, create a new array (new ArrayList<>()) every time.
Replace
elements.clear();
with
elements = new ArrayList<>(nbSommets);
Why elements.clear() clears the original ArrayList object
Because elements is still pointing to the original ArrayList object no matter whether you add it to an array, some other collection or object.
Why elements = new ArrayList<>(nbSommets) will work?
Because it will disconnect the reference to the original ArrayList object and point elements to a new ArrayList.
The problem is that if you create a List elements = new ArrayList(), you create a new object. If you put the list inside your array by rang[???] = elements, now your array contains reference to the List you have created. So your elements variable is pointing to the same object as as rang[???]. You can put it to array by rang[???] = new ArrayList(elements) and you will get a new List, and when you clear elements, the List in array will remain untouched.
I have three ArrayLists:
One is used for storing user input in the order they were entered, located in the main class.
Second one is exactly the same as the first one, but it is passed into a method called remTrip to be copied and will return the result.
Third one is list1 in the code below, which is the one being processed.
public static ArrayList<String> remTrip( ArrayList<String> a){
//code here
ArrayList<String> list1 = a;
Collections.sort(list1);
//code to remove triplicates from the list and returns the result
}
I wanted to keep the first ArrayList<String> in the same order it was (i.e. {"dog", "cat" , "tiger", "cat", "cat"} ), but apparently the Collections.sort() sorts all of the ArrayLists.
How do I sort only one of the list and not the others?
The problem is not how Collections.sort() works. The problem is that instead of creating a copy of your list, you set the new list equal to your list. This means that they both point to the same object, sorting one will sort the other because they are the same thing. To solve this set list1 to a copy of a instead of setting them equal.
You should be able to do
ArrayList<String> list1 = new ArrayList<String>(a);
Three arralists you're talking about are not 3 different arraylists. They're just three different references to the same arraylist.
What you're doing essentially is -
List list01 = new ArrayList();
List list02 = list01;
List list03 = list01;
What you want is -
List list01 = new ArrayList();
List list02 = new ArrayList(list01);
List list03 = new ArrayList(list01);
But you should remember, this way will give you a copy of your List, not all it's elements. So, if you change one of the elements in your copied List, it will be changed in your original List too.
How to solve it - Hint copy constructor.
I'm fairly new to Java so I hope I'm explaining this scenario correctly.
I'm trying to copy a List object, but want my second copy to point to the same object as the first List object. The only reason I need two copies is that I need to iterate through each one independently. I've tried to find a way and have even asked several colleagues, but the only thing that's working is to create another object all together.
Any help would be very much appreciated.
Thanks,
Christine
Update: Here's an example of what I'm trying to do:
This is how I currently have the lists declared:
List monetaryTransactions = null;
//make a copy of the monetary trans list for use when info is needed about a parent transaction
List parentMonetaryTransactions = new ArrayList(monetaryTransactions);
And this is how I'm using them:
//THE monetaryTransactions LIST IS POPULATED AND THEN.....
//loop through the monetary transactions list
for (Iterator iter = monetaryTransactions.iterator(); iter.hasNext();) {
monetaryTransaction = (IMonetaryTransaction) iter.next();
.....
//if there is a parent transaction get info about that transaction
if ( monetaryTransaction.getParentBillingTransactionId() != null) {
//get the parent billing trans id of the current monetary transaction
parentBillingTransId = monetaryTransaction.getParentBillingTransactionId();
IT'S THIS SECOND SORT AND ITERATION THAT I NEED TO MAKE SURE DOES NOT AFFECT MY OUTTER LOOP'S ITERATION
Collections.sort(parentMonetaryTransactions, new MonetaryTransactionOriginalProcessDateDescOrderComparator());
//loop through parent monetary trans list to find the parent transaction
for (Iterator iter2 = parentMonetaryTransactions.iterator(); iter2.hasNext();) {
parentMonetaryTransaction = (IMonetaryTransaction) iter2.next();
.......
}
}
}
You variable reference to the list can be thought of as a pointer to that object's instance. So you can create any arbitrary number of pointers to your list.
List<String> list = new ArrayList<>();
List<String> anotherPointer = list;
Now anything you with the references list and anotherPointer will reflect on the object itself.
list.add("Hello");
System.out.println(anotherPointer.size()); //Prints 1
Note that this piece of code will throw a NullPointerException:
List monetaryTransactions = null;
//make a copy of the monetary trans list for use when info is needed about a parent transaction
List parentMonetaryTransactions = new ArrayList(monetaryTransactions);
Going further down, why do you need to sort and iterate through the list again? Does each IMonetaryTransaction have more than one parent, with different Original Process Dates? Do different transactions share the same ID?
If you have access to the IMonetaryTransaction source, it would be cleaner to keep a reference to the parent transaction itself rather than store just the ID. E.g.
interface IMonetaryTransaction {
// This...
IMonetaryTransaction getParentBillingTransaction();
// ...rather than this
long getParentBillingTransactionId();
}
But if you can't change this model, and only have a flat list of all transactions, parents mixed in with children, it might be easier (and more efficient) to create a Map of transactions by ID:
Map<Long, IMonetaryTransaction> transactions = new HashMap<>();
monetaryTransactions.forEach(txn -> transactions.put(txn.getId(), txn);
So that when you need to get the parent of a given transaction, you just need to do this instead of iterating through the entire list again.
IMonetaryTransaction parent = transactions.get(txn. getParentBillingTransactionId());
If you don't want to create another List object you can use two int variables along with the get(int index) function to access the List at different indices.
I am using two java List objects that contain some data.
the first list contains all the data objects inside it and teh second one contains some of the data(not all) from the original list.
The original list itself is a static object that can be accessed .
Here is the code below that copies the whole contents of the original list into a new List and then ammends the copied list my removing certain elements.
The issue i am having is that it seems to effect and remove same elements from the Original list!
private List<Device> deviceList;
deviceList = App.devices;
//check which devices have not been added by checking the position data
for (Iterator<Device> iterator = deviceList.iterator(); iterator.hasNext(); ) {
Device device = iterator.next();
if (device.getPosition() != Device.NO_POSITION) {
iterator.remove();
}
}
In this line of code:
deviceList = App.devices;
you are not copying the list, but creating another reference to it.
To make a shallow copy of the list you can use for example: ArrayList constructor which accepts Collection as a parameter and makes copy.
So it should be like that:
private List<Device> deviceList = new ArrayList(App.devices);
deviceList = App.devices; does not create a new object but it just points on the App.devices object. You could use ArrayList deviceList = new ArrayList(App.devices). This one will instatiate a new object ArrayList and it will not effect your static list object.
However, keep in mind that any change on your object Device will be applied on both on your lists too, because both objects inside those two lists are pointing on the same adress. So if you want to apply individual changes to your objects inside your deviceList, you should create new Device objects as well. You might want to take a look at Deep and Shallow copy.
I have a 2D ArrayList. The ArrayList contains 10 ArrayLists. I tried the following code:
This is the main 2D ArrayList. Inside the main ArrayList there are10 ArrayLists:
ArrayList<ArrayList<Items>> arrayList = new ArrayList<ArrayList<Items>>();
Here I tried to create a copy of one of the ArrayList (selectedRow is just a number which says which ArrayList I get)
ArrayList<Items> newList = new ArrayList<Items>(arrayList.get(selectedRow));
After that I create another ArrayList:
ArrayList<Items> changeList = new ArrayList<Items>(it.returnTheNewArrayList(newList,randomItem));
Then in another class I created this method. The purpose of this method is to change an attribute of one of the objects.
public ArrayList<Items> returnTheNewArrayList(ArrayList<Items> a,int item){
int randomBin = r.nextInt(50);
for(Items i:a){
if(item==i.itemIds()){
while(randomBin==i.bins()){
randomBin = r.nextInt(50);
}
i.setBin(randomBin);
}
}
return a;
}
Finally, I set the new ArrayList in the 2D ArrayList
arrayList.set(whichList, changeList);
This is the procedure. I have find out, that when I run this procedure, both newList and changeList are the same. In both of these ArrayLists I'm saving the change I did in the method returnTheNewArrayList (I found out it with the debugging). But I want to change only one (the changeList).
What did I do wrong?
The lists contain references to objects. When you call i.setBin(...) that's (presumably) making a change to the object itself.
Each list has an independent copy of the references - so you could remove an element from one list without affecting the other - but they're only references.
Imagine you gave two people clipboards, with the same list of home addresses on. One person went and painted the front door of every house list on their clipboard red, then the second person visited all the same houses. The second person would see red doors, wouldn't they? It's the same thing here. The lists contain references, not objects.
If you want the lists to be completely independent, you'll need to populate them with references to different objects.
EDIT: I've just noticed that you'll also need to change your returnTheNewArrayList method, which actually isn't even creating a new ArrayList in the first place!
public ArrayList<Items> returnTheNewArrayList(ArrayList<Items> a,int item) {
// Stuff which doesn't change the value of a...
return a;
}
Again, the value of a is just a reference to the list... so when you return the same reference back, you're not returning a new ArrayList at all.
You really need to understand how references and objects work in Java - it's absolutely crucial to working with the language.
Inside of the returnTheNewArrayList method, you first need to clone a. Otherwise you will be modifying the original ArrayList and the original Items. Jon did a nice job of explaining why, so I won't go into it here. Your code could look something like:
ArrayList<Items> clone = new ArrayList<Items>(a.size());
for(Items item: a) clone.add(item.clone());
//modify clone here
return clone;
Since you've written the Items class yourself, you will need to implement the Cloneable interface yourself.
See the clone method's wikipedia page for more information.
The newList and changeList are not the same (not == ) but their content are identical.
Your "Item" objects are passed by reference that's why the two lists references the same Items.
To get a brand new reference you should create a new instance of Item in method returnTheNewArrayList (10 new instances for 10 new references.)
public ArrayList<Items> returnTheNewArrayList(ArrayList<Items> a,int item){
//create a new List
ArrayList<Items> newList = new ArrayList<Items>();
int randomBin = r.nextInt(50);
for(Items oldItem:a){
// make a copy of Item to get a new instance of Item for the new List
Item newItem = new Item(oldItem);
if(item==newItem.itemIds()){
while(randomBin==newItem.bins()){
randomBin = r.nextInt(50);
}
newItem.setBin(randomBin);
}
newList.add(newItem);
}
return newList;
}