Passing multi-dimensional arrays - java

I wrote the following code. It works great, but I have a question (so I don't bomb any future additions). Here's the code:
public class MoreStuff extends javax.swing.JFrame {
// Globals
int quiz[][]; // Used for Quiz subroutines
...
private void btnGetQuizActionPerformed(java.awt.event.ActionEvent evt) {
Functions fns = new Functions();
String strout;
int i = 0;
// Get the quiz
quiz = fns.GetQuiz();
The fns.GetQuiz() returns a 2-dimensional array perfectly.
My question is this: Having declared a multidimensional array at the class level, when the computer executes quiz = fns.GetQuiz, have I passed an object or have I only copied a reference?

Let's say GetQuiz()'s implementation is simply:
public int[][] GetQuiz() {
int[][] someArray = new int[10][];
return someArray;
}
The line int[][] someArray = new int[10][]; allocates an array on the heap and assigns a reference to that object to someArray.
When the method GetQuiz() finishes executing, the only thing "destroyed" is someArray, which is simply the reference to the array. The array itself lives on the heap, and only becomes eligible for garbage collection once there are no more references to the array.
In your example, because a copy of the reference is assigned to the quiz variable, even when someArray is destroyed, you still have quiz's reference pointing to the array, so the garbage collector will not try to destroy the array.
I think you might find the information in this thread helpful: Stack and Heap memory in Java.

In your program, quiz will hold its value even after the execution of btnGetQuizActionPerformed() because it receives a copy of the reference tofns.

Related

Vague question regarding number of instances in a program

I have a question which I consider to be rather vague.
How many objects(instances) of class A are created by the following method:
void create() {
A a;
A b;
A[] s;
a = new A();
b = a;
s = new A[10];
}
class A { }
I am not sure how to count the array. We can easily see that the objects a and b are the same, but do we consider the array itself to be an object, or do we consider that it has 10 objects, which are null?
I thank you in advance!
s = new A[10] is an object of A[], it's not an object of class A.
Therefore, you don't count the 10 null references of the array.
only a = new A() is created.
I ran the above code through the Eclipse profiler and found that only one instance was created a = new A() which b also references. Hence there was only one instance created. The array of type A was not allocated as null until I assigned an object to the first index of the array. Hope this helps.

Delete object's variable after instantiation

So I have an object which needs certain variables to be instantiated. These variables are passed to the object through an array of objects. Then, each element in the array gets assigned to an internal variable.
Does this array get garbage collected after the internal variables are assigned and the array is never referenced again, or should it be manually done?
class MyObject () {
public static Object [] values;
public void setvalues(inputArray) {
values = inputArray;
}
}
Memory is kind of important because I need to create a few hundred of these objects plus the rest of the code.
Whether the array is eligible for GC depends on this condition:
Is there anything still referencing the array?
If, you have something like this:
public class Foo {
private int[] myArray = {1, 2, 3, 4};
YourObject obj;
public void someMethod() {
obj = new YourObject(myArray);
}
}
Then myArray is not eligible for garbage collection because the variable myArray in the Foo object is still referencing it. You can then set myArray to null to make it eligible for GC.
If myArray were a local variable, however:
public class Foo {
YourObject obj;
public void someMethod() {
int[] myArray = {1, 2, 3, 4};
obj = new YourObject(myArray);
}
}
Then it is eligible for GC after someMethod returns because myArray will have gone out of scope by then.
Also, note that "eligible for GC" doesn't mean "will be collected immediately". It just mean that the GC has a possibility of collecting it in the future. When exactly? We don't know.
I am assuming your code looks like this
//Client class
o.setValues(arrayOfObjects);
//In the receiving object
public void setValues (Object[] objects){
// Dostuff
}
Two things need to happen for arrayOfObjects to be a candidate for GC -
arrayOfObjects needs to go out of scope. OR
arrayOfObject needs to be assigned another value or null.
If you are really concerned about memory, I would surmise it's the contents of the array that need to be garbage collected, not the array itself. The contents will clearly be referenced by the receiving object, so they will not be garbage collected.
Hope this helps.

Arrays and Referencing [duplicate]

This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 8 years ago.
Consider the following code:
public static void resize(int[] x){
x = new int[x.length*2];
System.out.println(x.length + " ");
}
public static void main(String[] args){
int[] x = {1,2};
resize(x);
System.out.println(x.length);
}
The output is "4 2". The question is: I thought that when we are defining an array in the code of the new length, the other array (the previous one with length 2) would be discarded, as now the value of the array points to the "larger" array. So, why would then print out at the end as length 2? I used Arrays.toString to verify, and indeed, the actual values of the array after the void method are {1,2}. This is confusing, as I thought that the array itself would be changed as the value is a pointer to the memory address (in contrast with using the method on a char/int variable, which would not affect the value of the variable).
When you call resize, you pass an array object to the method. This is the basic flow of your program:
initialize array of size 2
pass that array to resize()
resize has a reference to the value of the array
resize points it's reference to a new array twice the size of the old reference
prints "4"
main() prints the size of the initial array "2"
You don't change the original array in the new method, it merely has an array of the same value.
Because Java passes by value, the array doesn't change after your call to resize. (I'm assuming the output is actually 4 2, not 2 4.)
If you want resize to effect a permanent change, you should have the method return x; as its final statement (or use a global variable):
public static int[] resize(int[] x){
x = new int[x.length*2];
System.out.println(x.length + " ");
return x;
}
public static void main(String[] args){
int[] x = {1,2};
x = resize(x);
System.out.println(x.length);
}
The scope of your x variable in resize
public static void resize(int[] x){
x = new int[x.length*2];
}
is local to that function. It does not affect the x that was passed in. This means that as soon as resize completes, that local copy disappears and is eventually garbage collected.
If you want to resize the original array, return it. For example:
public static int[] getNewArrayOfDoubleLength(int orig_length){
return new int[orig_length * 2];
}
And call it with
x = getNewArrayOfDoubleLength(x.length);
Since arrays are immutable, this is a new array. The original one still exists (although it's inaccessible) until it's garbage collected.

"Final" in java and copying 2D arrays

I am having a little trouble understanding the concept of final in Java.
I have a class that follows:
public class MyClass
{
private int[][] myArray; // intended to be changed
private final int[][] MYARRAY_ORIGINAL; // intended to be unchangable
public MyClass(int[][] array)
{
myArray = array;
MYARRAY_ORIGINAL = array;
}
}
I was under the understanding that final would make MYARRAY_ORIGINAL read only. But I have tried editing myArray, and it edits MYARRAY_ORIGINAL as well. My question is, in this context, what exactly does final do? And for extra credit, how can I copy the array passed through the constructor into MYARRAY_ORIGINAL so that I can have 2 arrays, one to edit, and one that will remain preserved?
Your final MYARRAY_ORIGINAL is indeed read only: you can't assign a new value to the MYARRAY_ORIGINAL reference in other side than class constructor or attribute declaration:
public void someMethod() {
//it won't compile
MYARRAY_ORIGINAL = new int[X][];
}
The values inside the array are not final. Those values can change anytime in the code.
public void anotherMethod() {
MYARRAY_ORIGINAL[0][0] = 25;
//later in the code...
MYARRAY_ORIGINAL[0][0] = 30; //it works!
}
If you indeed need a List of final elements, in other words, a List whose elements can't be modified, you can use Collections.unmodifiableList:
List<Integer> items = Collections.unmodifiableList(Arrays.asList(0,1,2,3));
The last piece of code was taken from here: Immutable array in Java
In case of Objects, final makes reference can't be changed, but object state can be changed.
That is the reason why you are able to change values of final MYARRAY_ORIGINAL
MYARRAY_ORIGINAL is indeed read only variable. Your array reference can not be assigned a new value nor for their length of the arrays can be changed. A final variables initialization can be deferred till the constructors is called. If one tries to modify the reference of the final variable, compiler will throw an error message. But what is possible is, one can edit the elements of the MYARRAY_ORIGINAL and of the myArray i.e one can change the state of the object assigned to a final variable. For example
Class A {
final int[] array;
public A() {
array = new int[10] // deferred initialization of a final variable
array[0] = 10;
}
public void method() {
array[0] = 3; // it is allowed
array = new int[20] // not allowed and compiler will throw an error
}
}
To understand more on final please take a look at Java Language Specification on final variable.
Final does not mean 'read-only' per se, but more so "safe publication' for other threads than the one to which it is defined. Another aim of 'final' is that it ensures the latest object available in a multi-thread environment.
Secondly, if you define something as "final", for example:
private final int[][] MYARRAY_ORIGINAL;
The reference is "final", but not the object itself. A much better way to understand it would be this:
public static final List myList = new ArrayList();
Now I can access myList from any other threads - I can modify it (add to it); but I cannot
(a) Declare it again - myList = new ArrayList();
(b) Assign it another list - myList = anotherList;
The context for final I would see best, in a multiple-thread scenario.
Bonus: to answer your question, you cannot make a 'readonly' array, you will have to manage that yourself (as final, only maintains 'read-only' to reference not object)
You can use the method System.arraycopy to make a copy of the array as follows -
int[][] source = {{1,2},{3,4}};
int[][] copy = new int[source.length][];
System.arraycopy(source, 0, copy, 0, source.length);
Also, you some problem with your code regarding what you are trying to do. If you look at the constructor
public MyClass(int[][] array) { //something else passes the array
myArray = array;
MYARRAY_ORIGINAL = array; // you are just keeping a reference to it can be modified from outside
}
If you really want nobody to modify the values in that array MYARRAY_ORIGINAL, you should make a copy of the source array that comes comes from outside.
public MyClass(int[][] array) {
myArray = array; //make a copy here also if you don't want to edit the argument array
MYARRAY_ORIGINAL = new int[array.length][];
System.arraycopy(array, 0, MYARRAY_ORIGINAL, 0, array.length);
}
Now you shouldn't have to worry about the array's being modified from outside.

Array and methods?

I'm doing a task for a course in Java programming and I'm not sure how the following thing is working? The method below takes the value from an array and a integer. The integer should be added to the array and then be used outside the method in other methods and so on, but how could this work when the method has no return for the new content of the array? There is a void in the method? Have I missed something? Preciate some help? Is there something about pointers?
public static void makeTransaction(int[] trans, int amount);
Arrays in Java are objects. If you modify the trans array inside the method, the changes will be reflected outside of it1. Eg:
public static void modify(int[] arr)
{
arr[0] = 10;
}
public static void main(...)
{
int x = {1, 2, 3};
System.out.println(x[0]); // prints 1
modify(x);
System.out.println(x[0]); // now it prints 10
}
Note that native arrays can't be dynamically resized in Java. You will have to use something like ArrayList if you need to do that. Alternatively you can change the return type to int[] and return a new array with the new element "appended" to the old array:
public static int[] makeTransaction(int[] trans, int amount)
{
int[] new_trans = Arrays.copyOf(trans, trans.length + 1);
new_trans[trans.length] = amount;
return new_trans;
}
1 It is also worth noting that as objects, array references are passed by value, so the following code has no effect whatsoever outside of the method:
public void no_change(int[] arr)
{
arr = new int[arr.length];
}
You can't add anything to an array. Java arrays have a fixed length. So indeed, what you want to do is impossible. You might make the method return an int[] array, but it would be a whole new array, containing all the elements of the initial one + the amount passed as argument.
If you want to add something to an array-like structure, use an ArrayList<Integer>.
Do you have to keep the method signature as is?
Also, can you be a bit more specific. When you say "the integer should be added to the array", are you referring to the amount argument? If so, then how is that amount added? Do we place it somewhere in the array or is it placed at the end, thus extending the array's length?
As far as pointers go, Java's pointers are implicit, so if you don't have a strong enough knowledge of the language, then it might not be so clear to you. Anyways, I believe that Java methods usually will pass objects by reference, and primitives by value. But, even that isn't entirely true. If you were to assign your object argument to new object, when the method terminates, the variable that you passed to the method is the same after the method executed as it was before. But, if you were to change the argument's member attributes, then when the method terminated those attributes values will be the same as they were inside of the method.
Anyways, back to your question, I believe that will work because an array is an object. So, if you were to do the following:
public static void makeTransaction(int[] trans, int amount)
{
trans[0] = amount;
}
// static int i;
/**
* #param args
*/
public static void main(String[] args)
{
int[] trans = {0,1,3};
makeTransaction(trans, 10);
for(int i = 0; i<trans.length; i++)
{
System.out.println(trans[i]);
}
}
The output of the array will be:
10
1
3
But, watch this. What if I decided to implement makeTransaction like so:
public static void makeTransaction(int[] trans, int amount)
{
trans[0] = amount;
trans = new int[3];
}
What do you think that the output will be? Will it be set to all zero's or will be the same as it was before? The answer is that the output will be the same as it was before. This ties in to what I was saying earlier.
I might've assigned that pointer to a new object in memory, but your copy of the pointer inside of the main method remains the same. It still points to the same place in memory as it did before. When the makeTransaction method terminates, the new int[3] object that I created inside of it is available for garbage collection. The original array remains intact. So, when people say that Java passes objects by reference, it's really more like passing objects' references by value.

Categories