Just a thought question here. In C++, I could do the following:
vector<vector<string> > data;
// add data into data
//..
data[0].push_back( "somedata" );
And I would expect somedata to get written to the vector array because the [] notation gives me access to the object by reference. What about in Java? If I:
List<List<String>> data = new ArrayList<List<String>>();
// add data into data
//..
data.get(0).add( "somedata" );
Would this actually write somedata into the data object? Or would it create a new copy of the element at data(0), add somedata to that, and then that object disappears into GC sometime down the line?
ArrayList is a List backed-up by array (in order to enable random access) the list stores references to real elements so when you add a new element as you mentioned, the reference to it will be added to the ArrayList (and the backing Array will point to this List element).
You must first understand that List, String, etc. in Java, these types are reference types. Their values are references, which are pointers to objects. Thus, List<List<String>> in Java would be most equivalent to vector<vector<string *> *> * in C++. You cannot have a direct "object value" in Java like you can in C++; objects are always hidden behind a pointer.
So to answer your question, yes, the Java code you show works, but for very different reasons. In your Java code, you have a list of references (pointers). You want to modify stuff in the object that is pointed to by one of these pointers, but you do not need to change the pointer itself. Thus, there is no need to return the element by reference. It is sufficient to return the element (a pointer) by value.
Your question "Would this actually write somedata into the data object?" is kind of ambiguous. The code modifies the object pointed to by the first element of the list. Whether this constitutes modifying the list object itself depends on what you consider to be "part of" an object. As explained earlier, the list object contains a collection of pointers to objects. Should the objects pointed to by these pointers to be considered "part of" the list object? There could be many pointers to the same object. So if you consider it to be a part of the container, then what happens when there are pointers to the same object in multiple containers, is the object then part of all of these containers at the same time?
The answer to "Or would it create a new copy of the element at data(0)" is, it creates a copy of the pointer that is the first element. It does not create a copy of the object that the pointer points to.
Almost. The pattern you need is:
List<List<String>> data = new ArrayList<List<String>>();
data.add(new List<String>());
data.get(0).add( "somedata" );
The first line creates only the "outer" List of Lists; you have to populate it with one or more Lists (of Strings) before you can add data to the inner lists.
Related
I have a problem with understanding one thing.
I have:
List<Map> resultList = new ArrayList<Map>();
Then this resultList is filled with some data
resultList.addAll(somemethod(something, something, else));
Later in the method I have this kind of code:
Map timeSpan = someMethod(resultList, date);
timeSpan.put(KEY_ART, VALUE_ART);
timeSpan.put(KEY_TIMESPAN, true);
So I have a question now. If Map timeSpan is a map referenced to an element of List<Map> resultList, is using the put() method on the timeSpan map affecting the element in resultList?
I am asking this question cause a collegue told me that this is working this way - modifying an element in timeSpan is also modyfying this element in resultList. She is far more experienced, and I don't just want to believe her but I want to understand why it is working this way.
You have to remember that resultList is a reference to an object. You can copy this reference around and use it in many way, in many places but there is only one object. This means when you alter the object, there is only one view of this object.
Java objects are always instantiated as a reference to a memory space. If you create a second object from the first object, both will point to the same memory space:
Map a = new HashMap();
Map B=b = a;
Here, we first create an instance A which points to a HashMap which is created somewhere in memory. Next, we create an instance of Map b and have it reference to the same memory space as Map a. Now, when we change map b, these changes will also be made to Map a, since they point to the same memory construct.
In you case, you have a List this in itself is a memory construct. Each item in the list references a seperate Map. These are each also created somewhere in memory. The moment you retreive a Map from the list, you retreive the reference to the memory space where the actual map is located. After that, it works exactly as the example.
addAll() will copy all the elements to the current list from the Collection/List you passed as an argument to this method. In your case, as each element is a reference to Map object, after copying, you have 2 references pointing to same Map object, so changes done using any one reference are visible through the other one.
The short answer is yes, put() for timeSpan is affecting resultList, because when a method returns a Map, which is got from the List, it returns a reference to the heap where map elements are located.
I have encountered a problem in one of my Java projects, which causes bugs.
The problem sounds as following:
I have two arrays. Let's name them firstArray and secondArray. Object in this case is a seperate class created by me. It works, the array can be filled with objects of that type.
Object[] firstArray= new Object[];
Object[] secondArray = new Object[];
Now, when I get an element out of the first array, edit it and then copy it in the second array, the object from the first array gets altered too.
tempObj = firstArray[3];
tempObj.modifySomething();
secondArray[3] = tempObj;
Whenever I do this, the (in this case) 3rd element(actually 4th) of the first array gets the modifications. I don't want this. I want the first Array to remain intact, unmodified, and the objects I have extracted from the first array and then modified should be stored in the second so that the second array is actually the first array after some code has been run.
P.S. Even if I get the element from the first array with Array.get(Array, index) and then modify it, the element still gets modified in the first array.
Hopefully you understood what I wanted to say, and if so, please lend me a hand :)
Thank you!
You're going to have to create a new object.
The problem is the modifySomething call. When you do that, it alters the object on which it's called. So if you've only got one object (even by two names), you can't call modifySomething or they will both change.
When you say secondArray[3] = firstArray[3], you aren't creating a new object: you're just assigning a reference. Going through an intermediate temporary reference doesn't change that.
You'll need code that looks like this:
Object tempObj = firstArray[3].clone();
tempObj.modifySomething();
secondArray[3] = tempObj;
The clone() method must return a new object divorced from the original but having identical properties.
When you retrieve an element from your array, you have a reference to it. So if you modify it, the modification are shered through all the object's references.
In order to leave it intact, you should use some method like Object.clone() or create a new Object and use its constructor to initialize its fields.
The object extracted from the first array needs to be cloned to create a new instance that is seperate. Otherwise the modification will affect the object in the first array as it is the same object.
When you retrieve an element from your array, you get a reference to it. So if you modify it, the modification are shared through all the object's references.
In order to leave it intact, you should use some method like Object.clone() or create a new method which take in input your retrieved object and return a new one alike.
In Java, when you do this secondArray[3] = tempObj;, you actually put the reference to the array, not the real object
So firstArray[3] and secondArray[3] point to the same real object
What you need to do is to create a new object that is identical to your original object, and put the reference of the new object to your secondArray
It might worth to point out that default clone() function only does a shallow copy, so if you have mutable objects in your object's fields, it might cause some problems. Take a look at this article about how to do a deep copy
When list.addAll(list2) is called will objects in lists be copied to list? or just copy their references... did not find any explanation on javadoc...
No copy of the objects or their data are made; their references are simply added to the list object.
No, the objects will not be copied; references to the same objects will be added to the list.
In general, java will not copy objects when you "add all", that is, for objects, pointers to the originals are used.
* But be careful ! For strings, due to immutability, an array copy will not point to the original string values, and you must not expect that changing a pointer to a string that was added to an array list will result in a new value inside the array list.
so suppose i have
ArrayList<E> X = new ArrayList<E>();
and I pass X into some parameter:
Something Y = new Something(X);
it will pass X by reference rather than by value and I don't want this....class Something has a field with Arraylist type that is supposed to be distinct to itself and I don't want to go and iterate through the damn arraylist and set it individually just to instantiate the field...
is there a way to easily make Java pass any object parameters by value rather than reference without having have to implement cloneable interface on all my objects which is a pain in the butt
As Java do not allow direct pointer manipulation, you cannot dereference a pointer. You have to live with references. If you want to prevent the passed object from being modified, you have to clone it or make it immutable (like String). Also keep in mind that object references are passed-by-value. So statements like "Java has pass-by-reference" is not exact, if we take pass-by-reference in the C++ sense.
It actually passes X by value. (The Something constructor can't change the variable X in the calling code.) X happens to be a reference to an ArrayList, not an ArrayList. You could try:
Something Y = new Something(new ArrayList<E>(X));
Instead of creating a new object everytime you can pass an unmodifiable list. This list is read-only and the user has to create another list if he wants to make any modification.
List unmodifiableList = Collections.unmodifiableList(list);
List newList = new ArrayList(unmodifiableList);
Collections.sort(newList);
The constructor of ArrayList takes an existing list, reads its elements (without modifying them!), and adds them to the new List.
In Java, we can always use an array to store object reference. Then we have an ArrayList or HashTable which is automatically expandable to store objects. But does anyone know a native way to have an auto-expandable array of object references?
Edit: What I mean is I want to know if the Java API has some class with the ability to store references to objects (but not storing the actual object like XXXList or HashTable do) AND the ability of auto-expansion.
Java arrays are, by their definition, fixed size. If you need auto-growth, you use XXXList classes.
EDIT - question has been clarified a bit
When I was first starting to learn Java (coming from a C and C++ background), this was probably one of the first things that tripped me up. Hopefully I can shed some light.
Unlike C++, Object arrays in Java do not store objects. They store object references.
In C++, if you declared something similar to:
String myStrings[10];
You would get 10 String objects. At this point, it would be perfectly legal to do something like println(myStrings[5].length); - you'd get '0' - the default constructor for String creates an empty string with length 0.
In Java, when you construct a new array, you get an empty container that can hold 10 String references. So the call:
String[] myStrings = new String[10];
println(myStringsp[5].length);
would throw a null pointer exception, because you haven't actually placed a String reference into the array yet.
If you are coming from a C++ background, think of new String[10] as being equivalent to new (String *)[10] from C++.
So, with that in mind, it should be fairly clear why ArrayList is the solution for an auto expanding array of objects (and in fact, ArrayList is implemented using simple arrays, with a growth algorithm built in that allocates new expanded arrays as needed and copies the content from the old to the new).
In practice, there are actually relatively few situations where we use arrays. If you are writing a container (something akin to ArrayList, or a BTree), then they are useful, or if you are doing a lot of low level byte manipulation - but at the level that most development occurs, using one of the Collections classes is by far the preferred technique.
All the classes implementing Collection are expandable and store only references: you don't store objects, you create them in some data space and only manipulate references to them, until they go out of scope without reference on them.
You can put a reference to an object in two or more Collections. That's how you can have sorted hash tables and such...
What do you mean by "native" way? If you want an expandable list f objects then you can use the ArrayList. With List collections you have the get(index) method that allows you to access objects in the list by index which gives you similar functionality to an array. Internally the ArrayList is implemented with an array and the ArrayList handles expanding it automatically for you.
Straight from the Array Java Tutorials on the sun webpage:
-> An array is a container object that holds a fixed number of values of a single type.
Because the size of the array is declared when it is created, there is actually no way to expand it afterwards. The whole purpose of declaring an array of a certain size is to only allocate as much memory as will likely be used when the program is executed. What you could do is declare a second array that is a function based on the size of the original, copy all of the original elements into it, and then add the necessary new elements (although this isn't very 'automatic' :) ). Otherwise, as you and a few others have mentioned, the List Collections is the most efficient way to go.
In Java, all object variables are references. So
Foo myFoo = new Foo();
Foo anotherFoo = myFoo;
means that both variables are referring to the same object, not to two separate copies. Likewise, when you put an object in a Collection, you are only storing a reference to the object. Therefore using ArrayList or similar is the correct way to have an automatically expanding piece of storage.
There's no first-class language construct that does that that I'm aware of, if that's what you're looking for.
It's not very efficient, but if you're just appending to an array, you can use Apache Commons ArrayUtils.add(). It returns a copy of the original array with the additional element in it.
if you can write your code in javascript, yes, you can do that. javascript arrays are sparse arrays. it will expand whichever way you want.
you can write
a[0] = 4;
a[1000] = 434;
a[888] = "a string";