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?
Related
I just wanted to clarify this question I had for a while for more efficient and 'correct' code.
I gave a class 'Student' with objects in an array list of objects. I have another class called Class which has an array list of references to the very same objects in the Student class.
Should I declare the 'Class' class as
ArrayList<Student> myStudents = new ArrayList<Student>();
or
ArrayList<Class> myStudents = new ArrayList<Class>();
Also another part of the question is I have seen people declare arrayLists as ArrayList<Student> myStudents = new ArrayList<>();
where the second half of the carrots are left empty. What exactly does the difference mean? Does this mean that the array list is not an object of any class?
Thank you so much for your time and help
Cheers
It depends on what you want to store in the list rather than where you are using it. If you're storing Student objects, then you'll use ArrayList<Student>().
The type omitted on the right side is called type inference (added in java 7), which means the type parameter on the right side will be inferred from the type of the assignment variable on the left. It helps to write the code in a cleaner way. For e.g.
Writing below is easier:
List<Some<Type<Another>>> var = new ArrayList<>();
than:
List<Some<Type<Another>>> var = new ArrayList<Some<Type<Another>>>();
Technically, neither.
You would want to do:
List<Student> myStudents = new ArrayList<>();
if you want to create an ArrayList with Student objects and
List<Class> myClasses = new ArrayList<>();
if you want to create an ArrayList with Class objects.
1) Note the variable names.
2) Note that you should always try to code to an interface (the left side is a List, not an ArrayList). This allows much greater flexibility since you're not dependent on the specific implementation of an ArrayList later on. This point is so powerful! You can write method signatures to accept objects of type List and then use an ArrayList, LinkedList or Stack or any class that implements a List. Depending on how you are using your ArrayList later, the Collection interface may be sufficient instead.
The diamond operator allows the compiler to infer the value of the type argument without having to type it all out. It's needed for backward compatibility for older Java versions.
As a general practice for performance optimization, you will also want to supply an initial capacity of an ArrayList if it's possible. So if you know that there are only 5 classes, then you would do:
List<Class> myClasses = new ArrayList<>(5);
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
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
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
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.