Why is the new keyword used twice to create object arrays - java

I am new to Java and I have just dealt with object arrays. I'm curious as to why Java requires me to use the following syntax for arrays
SomeClass[] object = new SomeClass[50]; // any positive integer works
object[2] = new SomeClass(some, parameters);
As I understand it, the new keyword allocates the data for the instance in memory. I was wondering why Java uses the new keyword twice here. I think it should only have to use the new keyword once when the objects are initialized and not when they are declared. So, my question is: why does Java use the new keyword twice when creating object arrays?

Here, the new keyword is used twice because two objects are being created -- one array and one SomeClass that happens to be placed in the array.

The first one is to create an array of references. The second one is to create the actual object for every element in the array.

You need to create the container (an array in your case), and each element (which is also an object) that you intend to place in that container.
In your case, I note you've created an array with 50 elements. That means that you can index object[0] up to and including object[49]. When the container is created, each object[n] will be a null reference.

SomeClass[] object = new SomeClass[50];
allocates an array with 50 uninitialized references
object[2] = new SomeClass(some, parameters);
allocates and instantiates an object referred to by the third index in the array

Related

An Array of ArrayLists (Null Pointer Exception)

i'm currently trying to add items to an generic "array" of arraylists but for some reason i keep getting a null pointer exception. The Structure is initialised and both my array index reference and the reference to the object i'm passing in are both visible within the body of code right before the exception occurs. I'm almost sure its down to the way i either declared the data structure or my way im trying to add it in. Any advice would be appreciated. Thanks in advance
ArrayList<Site>[] group = (ArrayList<Site>[])new ArrayList[entranceSites.size()];
group[i].add(sIndex(path));
sIndex is a function I'm using to convert integers to graph sites and the object is not null when I'm passing it in so i'm sure its not the problem. I is initialised and also visible to the program.
new ArrayList[entranceSites.size()];
does not actually initialize the array elements with any constructor. The array will be filled with enteranceSites.size() null elements.
You will need to iterate through the array and actually construct ArrayList objects.
Here's how you can set each element of the array to a new ArrayList using Java 8:
Arrays.setAll(group, n -> new ArrayList<Site>());
(The second argument is a function of n, the array index, but n isn't actually used. You still need to include it.)
You have allocated an array of ArrayLists, but you have not allocated any actual ArrayLists inside that array. The array initially contains all null references. So your invocation to add is on a null reference and thus causes the exception. If you say:
group[i] = new ArrayList<Site>();
Before you call add it will work.
Note that it is generally a bad idea to mix primitive arrays and Java collections, and if you are new to Java, then you should probably stick to collections since they are going to be easier to work with.
You should also be aware that the cast you are making (ArrayList<Site>[]) is unchecked and will almost certainly generate a warning assuming you have warnings enabled, which you should be enabling warnings as a beginner. This is another reason why it is not a good idea to mix generics with primitive arrays.
By the looks of your code fragment, my guess is that you failed to initialize the ArrayList<Site> element being added to the array; thus, failing when calling the List.add() method. The array itself is properly initialized, but you are trying to add a Site to an ArrayList that has not been initialized properly.
For this to work, you must create your ArrayList<Site> object. Once your lists are properly instantiated, you can add them to the array. You can add Site objects when creating the list or after you add them to the array. It does not matter when because the space in memory will be already allocated. Suppose a company has sites in many states, for argument sake, New York. All of the sites in that geographical location will be added to the NY list of sites:
ArrayList<Site> nySites = new ArrayList<Site>();
Site site1 = new Site();
group[0] = nySites;
group[0].add(site1); // Now you can call the add() method

why can i not access a class array index

I keep getting a NullPointerException when I try to access elements of an array I created and don't know why. The code that throws:
TreeNode[] list1;
list1 = new TreeNode[1000];
list1[0].edges = new EdgeNode(1); //Throw line
but if I do this, it works:
TreeNode[] list1;
list1 = new TreeNode[1000];
list1[0] = new TreeNode();
list1[0].edges = new EdgeNode(1);
and I don't know why. Obviously I could for loop through the whole array and make new elements but doesn't that defeat the point of new? Also, if relevant, I have defined the default constructor for TreeNode.
You actually answered your own question: elements of an array should be individually initialized. By default they are null for array of objects. Hence NullPointerException.
This is exactly how java works. When you create an array, all elements are initialized to null, and you need to initialize them. That is because there is no way it could find out whether you just wanted them constructed with the default constructor, or with a different constructor with constant parameters, or a different constructor with varying parameters, or null, or what. So it just initializes the array to null.
After you say list1 = new TreeNode[1000],
list1 is a new array full of nulls.
So you have to loop through and initialise it
It does not defeat the point of new, because when you say new A[10000], that is allocating a new array, not its' elements. Saying list1[0] = new TreeNode(); allocates an element.
I agree this isn't elegant but that is java for you. :)
When you call new TreeNode[1000] you are instantiating an array of references, not the objects themselves. This is normal since the compiler can't just assume which constructor to call. Imagine if you had a class that didn't have a no-argument constructor: how do you think the compiler would have to instantiate it in that case?
There are two Initialization involved in this scenario
Initialization of the Array
Initialization of Array Elements
new TreeNode[1000] only initializes Array not Array Elements.
list1 = new TreeNode[1000];
This is only creating a new TreeNode array. The array itself is an object. So don't let the new keyword fool you. So with the above code, all you have is an array of TreeNode type. That only holds values of a TreeNode type. Does not give it any TreetNode` value. You must do that explicity yourself with code.
When you create new array of objects it is by default filled with nulls so when you are executing
list1[0].edges
in reality you are trying to execute
null.edges
which is incorrect since null doesn't have edges.
There are few reasons why arrays are not filled with new objects after being created:
In many (if not most) cases we want to place in array objects that already exists, so creating new ones would be waste of time.
Which constructor should compiler use to create objects that would fill array?
What arguments should be used in such constructor?
Remember that array can be array of classes that can't be instantiated like abstract classes or interfaces. How would compiler fill such array? Which subclass should be used?

Is it possible to change a variables value from an array

This is a little confusing question for me to express, but I'll do my best.
So:
ArrayList<Object> fieldList = new ArrayList<Object>();
I then dump a lot of different variables to this array:
fieldList.add(objectsURL); //string
fieldList.add(X); //int
fieldList.add(Y); //int
...
If I change the variable, the values in the array change
too-confirming the array stores a reference to the memory, rather
then value itself.
However, if I then retrieve data from the array then set that...
Object object = ((String)this.fieldList.get(0));
Then set object
object = "meeep!"
objectsURL is not set to "meep!" but rather it retains its original
value.
I assume this is because the "object" is not referencing the original
variable anymore, that instead its pointing to a new immutable string
in the memory.
All expected Java behavior I think....but then, how would I go about
setting the actual original variable? is this possible in java?.
So, in other words. Given only access to "fieldList" is it possible to change the value of
"objectsURL"?
So, if:
String objectsURL = "www.google.com"
fieldList.add(objectsURL);
Is there a way to set objectsURL to "www.stackoverflow.com" using only a reference from fieldList?
I dont want to change the fact that fieldList contains "objectsURL", I want to change what string the variable "objectsURL" actualy contains.
If not, is there an alternative method to achieve the same thing?
I hope my question explains the problem well enough.
My use-case is trying to make a serialization/
deserialization system for a bunch of my objects. I was hoping to put
all the fields into a arraylist I could retrieve for both reading and
writing....thus avoiding having to hard-code long lists of
field[0]=blah and blah=field[0] and then going though constant pains
of needing to renumber them each time I add a new field before
another.
(I cant use Javas inbuilt serialization, as I am using GWT and this is client side only.)
Thanks,
I assume this is because the "object" is not referencing the original variable anymore, that instead its pointing to a new immutable string in the memory.
Correct, each time you use the assignment operator = on an object you change the object it refers to, not the object itself.
To change the values in the List, you use the .set method of an ArrayList
this.fieldList.set(0, newValue);
Since your variable is a String, there is no way you can change the String-variable through the list
Your alternatives:
using a char-array
List myList = new ArrayList();
char[] charArray = "My String".toCharArray();
myList.add(charArray);
charArray[0] = 'A';
String theString = new String(myList.get(0)); // "Ay String"
If you use a char-array, make sure that the length of the array is enough to contain the number of characters you want to have in the future, because to change the length of the array you will need to create a new array (array lists can be expanded dynamically, arrays can not)
Embed the String inside your own class (I have ignored getters and setters here)
class MyString {
public String value;
public MyString(String value) {
this.value = value;
}
}
MyString myStr = new MyString("some value");
list.add(myStr);
((MyString) list.get(0)).value = "a new value";
System.out.println(myStr.value); // will print "a new value"
Strings are immutable, so it is impossible to change the contents of a String object. Also, you cannot use the list to change what object the reference variable objectsURL points to. To achieve what you want, you will need to create a custom class that has a String member. You can then store instances of this class in a List and change the String references to via the references in the list. The changes will then be reflected in any other reference variables which refer to the objects in the list.
First, you declare a variable 'object' and assign some Object out of the ArrayList. Later you assign some other object "meeep!" to this variable. There is no reason that your 'object' variable is related to the ArrayList.

Java get an element from an array, edit it, then store it in another array, without altering the first array

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

passing objects by value in java

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.

Categories