Copying Arrays The Right Way - java

I came across 2 examples from my notes which is about copying arrays.
The first example given below, stated that it is not the way to copy an array. But, when i tried to run the code, it managed to copy all the values from array1 to array2.
int []array1={2,4,6,8,10};
int []array2=array1;
for(int x:array2){
System.out.println(x);
}
The second example given, was saying the right way to copy an array.
int[] firstArray = {5, 10, 15, 20, 25 };
int[] secondArray = new int[5];
for (int i = 0; i < firstArray.length; i++)
secondArray[i] = firstArray[i];
My question is, are these 2 examples appropriate to be applied in coding or Example 2 is preferred. If you were my lecturer, I were to apply Example 1.. I will be given less mark compared to Example 2 method or just the same?

The first example doesn't copy anything. It assigns a reference of the original array to a new variable (array2), so both variables (array1 and array2) refer to the same array object.
The second example actually creates a second array and copies the contents of the original array to it.
There are other easier ways of copying arrays. You can use Arrays.copyOf or System.arraycopy instead of explicitly copying the elements of the array via a for loop.
int[] secondArray = Arrays.copyOf (firstArray, firstArray.length);
or
int[] secondArray = new int[firstArray.length];
System.arraycopy(firstArray, 0, secondArray, 0, firstArray.length);

Perfect way to copy elements is
System.arraycopy(array1,0, array2, 0, array1.length);
That above code is replacement for you second example which avoids a for loop.
And where in your first example, you are just referring the first array. So what ever changes happened to the first array can be seen from second array.
My question is, are these 2 examples appropriate to be applied in coding or Example 2 is preferred.
See again, they are not doing the something to compare. First one pointing to array reference and second snippet of code referencing elements it it. So you just can't compare them.
And there are other ways to copy array elements as well just like others mentioned and I prefer System.arraycopy because
1)Arrays.copyOf creates another array object internally and returns it where as System.arraycopy uses the passed array.
2) Clone is the too slow. Never use it unless you have no other choice.
There are few reasons I'm avoid clone. Here is
Josh Bloch analysis on clone vs copy constructor (when you clone individual elements).

To demonstrate the problem with the first method, try this:
int[] array1 = {2, 4, 6, 8, 10};
int[] array2 = array1;
array1[0] = 0;
System.out.println(array2[0]);
What do you think this will print?
0
It will print 0, because array2 now points to array1:
both variables now refer to the same object,
so modifying the content of any one of these will appear to modify both.
So your first method is NOT called copying an array.
It's a simple assignment, from one variable to another,
in this case assigning the value of array1 to array2,
so that both variables point to the same thing.
As for your second method,
here's a much simpler way to accomplish the same thing:
int[] array2 = array1.clone();

In your first example, you end up with only one array with two variables referring to it. Assignment only passes a reference to the array. So both firstArray and secondArray are pointing to the same array. It's not a copy. Try to set firstArray[0] = 99 and print secondArray and you'll see it's the same array.
In the second example, it's an actual copy - you have created a new array and copied each value. Now, assigning firstArray[0] = 99 won't change the array referred to by secondArray because it's a copy.
So the answer is: if you give the first way, you'll get lower marks.
In real use, there are better ways to copy arrays, using System.arraycopy, Arrays.copyOf or firstArray.clone().

int[] secondArray = new int[5];
In the second example, you are creating an array of int using new operator and copying the elements to it manually using for loop. Whenever you use new operator in java, a new memory allocation happens (object creation).
Where as in the first, it is just reference assignment, both are pointing to same array. You can easily verify that by changing the content of one array see the same effect into the second array. This will not happen in the second array copying.
int []array2=array1;

Related

Java array storing more than the upper bound

I was under the impression that storing and accessing data beyond the upper bound specified for arrays will result in Exception but I was coding a solution and I stumbled upon a scenario where the array stored more elements than the upper bound.
public static void main(String[] args) {
int[][] arr = new int[1][5];
String values = "1 2 3 4 5 6";
arr[0] = Arrays.asList(values.split(" ")).stream().mapToInt(Integer::parseInt).toArray();
for (int i : arr[0]) {
System.out.println(i);
}
}
The above program outputs 1 2 3 4 5 6 in separate lines while clearly I have specified my upperbound as 5. Can someone explain this weird phenomenon?
Can someone explain this weird phenomenon?
Here goes:
int[][] arr = new int[1][5];
is declaring an int[][] and initializing it to a structure consisting of one top-level int[][] of length 1, and one second level int[] subarray of length 5. The first cell of the former refers to the latter.
Then:
arr[0] = Arrays.asList(values.split(" "))
.stream()
.mapToInt(Integer::parseInt)
.toArray();
is creating an int[] of length 6 and assigning it to arr[0]. This replaces the int[] subarray of length 5 that was created in the earlier initialization.
The intuitive behavior is that the "shape" of arr changes from a int[1][5] to int[1][6] when you do that assignment.
You then commented:
"Ohh basically then it treats as an array initialization rather than an assignment then."
Strictly, no. If you think of arr[0] = ... as an array initialization, it gets confusing. It is actually an assignment of a newly create array of type int[] to a cell of an existing "array of int[]".
This may sound like a fine distinction, but it goes to the heart of the matter. If you read the JLS and the JVM specs deeply, you will see that Java array types and objects are fundamentally one dimensional. Thus int[][] is a syntactic shorthand1 for "array of int[]", and arr[i][j] is a shorthand for (arr[i])[j].
Thus when we do arr[0] = ... in the example, we are not initializing something. Instead, we are changing a data structure that was initialized previously. At least, that is the Java language perspective.
From the perspective of the class where this is happening, this could be getting something into the initial state that is required by the class semantics. Thus it is reasonable to call that "initialization" ... from that perspective.
1 - This shorthand is so ingrained in the language that there isn't any other way to write the type "array of int[]" using Java syntax. The syntax for array types comes from C via C++, though the particular Java semantics of arrays doesn't.
After assignment, arr[0] is holding a list object that has bounds set to whatever Arrays.asList defines.

How to calculate the number of elements in multidimentional arrays?

i've had this question ever since i learned two dimensional arrays... and i hope someone can clarify things for me..
here's what i know
int[] x= new int[2];
this one dimensional array has two elements.
int[][] y=new int[2][3];
this two dimensional array has six elements right? (2 x 3 = 6)
but when i look into the way a two dimensional array is actually made,
first a reference type variable named y that can store memory
addresses of a two-dimensional array is made in the stack.
then an object with two elements that can store one dimensional
memory addresses is made in the heap.
then another 2 one-dimensional arrays are made, each consisting 3
elements that can store int type values. and the memory addresses of
these two one dimensional arrays are assigned to the two elements
that were made earlier inside the object.
then this object's memory address is assigned to the y variable that
is in the stack.
now the problem i have is, only two elements are made inside that object in the beginning right? so doesn't that mean that the two dimensional array has two elements. and the two one-d arrays have 3 elements each?
all of these questions bugs me because y.length = 2 and y[0].length =3
please correct me if i am wrong and hope someone could help me. thanks
Yes, you're absolutely right. Java doesn't have 2-dimensional arrays per se. All it has is arrays containing arrays, and syntax sugar (new int[2][3]) to create them.
But you could indeed have an array containing arrays of different lengths:
int[][] array = new int[2][];
array[0] = new int[5];
array[1] = new int[3];
System.out.println(Arrays.deepToString(array));
// prints [[0, 0, 0, 0, 0], [0, 0, 0]]
So it you get an int[][] and want to know how many integers it contains, you need to loop through the outer array and sum the lengths of the inner arrays. Unless you have the guarantee that all inner arrays have the same length. In that case, you can multiply the length of the outer array by the length of any of the inner arrays.
In Java, multidimensional arrays are actually arrays of arrays. For example, a two dimensional array variable called arr looks like:
int arr[][] = new int[4][5];
This allocates a 4 by 5 array and assigns it to arr. Conceptually, this array will look like the one shown in the Figure:
When you allocate memory for a multidimensional array, you need only specify the
memory for the first (leftmost) dimension. You can allocate the remaining dimensions separately. For example:
int twoD[][] = new int[4][];
twoD[0] = new int[5];
twoD[1] = new int[5];
twoD[2] = new int[5];
twoD[3] = new int[5];
While there is no advantage to individually allocating the second dimension arrays in this situation, there may be some benefits. Like allocating dimensions manually, you do not need to allocate the same number of elements for each dimension. As stated earlier, since multidimensional arrays are actually arrays of arrays, the length of each array is under your control.
You could flatten your multidimensional Array with this method, and call List#size() on it.
It will even flatten nested Lists, Sets, Maps and Queues.

How is int[] []x[] a legal array declaration in Java?

int[] []x[];
I know that
int[] x;
int x[];
int []x;
and similar declares an array perfectly fine, but how does 3 sets for brackets, work exactly?
It is legal because Java Language Specification - 10.2. Array Variables allows it:
The array type of a variable depends on the bracket pairs that may appear as part of the type at the beginning of a variable declaration, or as part of the declarator for the variable, or both.
(emphasis mine)
So to put it simply int[] []x[]; is same as int[][][] x;.
Generally we should avoid mixed way of placing [] (or even placing [] after variable name). IMO it is because in Java we are used to declaring variables as
FullTypeDescription variableName
instead of
SomeTypeInfo variable RestOfTypeInformation
and number of arrays dimensions is part of type information, so it should be separated.
Mixed type is allowed to let us write code like (to let C or C++ programmers migrate to Java easier):
int[][] a, b[];
instead of
int[][] a;
int[][][] b;
but still last way is preferred.
Although the follow 3 mean the same, the first one is the recommended one, since the type of x is an array of integers.
int[] x; // Recommended
int x[];
int []x;
So, the other one should be:
int[][][] x;
Which is an array of array of array of integers.
Depending on how it is used, it can be thought of as a 3-dimensional array, e.g. see Fundamentals of Multidimensional Arrays
Of course, in reality, Java doesn't have multi-dimensional arrays. It is, as first stated, an array of array of array of integers, and each sub-array may have different lengths. But that is a longer topic.
Here's an example:
int[][] array = new int[1][2];
Above we have a double-dimensional array. Really, it's an array of arrays. So declaring it like so:
int[] array[] = new int[1][2];
You are still declaring an array of arrays, aka a double-dimensional array. this means that this:
int[] []array[] = new int[1][2][3];
Is the same as this:
int[][][] array = new int[1][2][3];
Because brackets after the array identifier ('array') were adapted for C programmers, they are treated as though they're located before the identifier.
Hope this helps! :)

C++ and Java array declaration/definition : differences

my question is really simple (which doesn't imply that the answer will be as simple.. :D )
why do arrays in C++ include the size as part of the type and Java's do not?
I know that Java array reference variables are just pointers to arrays on the heap,but so are C++ pointers to arrays,but I need to provide a size even then.
Let's analyze C++ first:
// in C++ :
// an array on the stack:
int array[*constexpr*];
// a bidimensional array on the stack:
int m_array[*constexpr1*][*constexpr2*];
// a multidimensional array on the stack:
int mm_array[*constexpr1*][*constexpr2*][*constexpr3*];
// a dynamic "array" on the heap:
int *array = new int[n];
// a dynamic bidimensional "array" on the heap:
int (*m_array)[*constexpr*] = new int[n][*constexpr*];
// a dynamic multidimensional "array" on the heap:
int (*mm_array)[*constexpr*][*constexpr*] = new int [n][*constexpr1*][*constexpr2*];
n doesn't have to be a compile time constant expression,all the elements are default initialized. Dynamically allocated "arrays" are not of type array,but the new expression yields a pointer to the first element.
So when I create a dynamic array,all dimensions apart the first one,must be constant expressions (otherwise I couldn't declare the pointer to hold their elements). Is it right??
Now to Java.I can only allocate array on the heap,since this is how Java works:
// a dynamic array on the heap:
int[] array = new int[n];
// a dynamic bidimensional array on the heap:
int[][] m_array = new int[n][];
// a dynamic multidimensional array on the heap:
int[][][] mm_array = new int [n][][];
In Java, it doesn't seem to care about array size when defining an array reference variable (it's an error in Java to explicitly provide a size),and so I just need to provide the size for the first dimension when creating the array. This allows me to create jagged array,which I'm not sure I can create in C++ (not arrays of pointers).
can someone explain me how's that? maybe what's happening behind the curtains should make it clear. Thanks.
That's because in Java, all arrays are single-dimensional. A two-dimensional array in Java is merely an array of references to one-dimensional arrays. A three-dimensional array in Java is merely a one-dimensional array of references to arrays of references to arrays of whatever base type you wanted.
Or in C++ speak, an array in Java, if it's not an array of primitive, it's an "array of pointers".
So, for example, this code:
int[][][] arr3D = new int [5][][];
System.out.println(Arrays.deepToString(arr3D));
Would yield the output:
[null, null, null, null, null]
You can decide to initialize one of its elements:
arr3D[2] = new int[3][];
And the output from the same println would now be:
[null, null, [null, null, null], null, null]
Still no ints here... Now we can add:
arr3D[2][2] = new int[7];
And now the result will be:
[null, null, [null, null, [0, 0, 0, 0, 0, 0, 0]], null, null]
So, you can see that this is an "array of pointers".
In C++, when you allocate a multi-dimensional array the way you described, you are allocating a contiguous array which actually holds all the dimensions of the array and is initialized all the way through to the ints. To be able to know whether it's a 10x10x10 array or a 100x10 array, you have to mention the sizes.
Further explanation
In C++, the declaration
int (*mm_array)[5][3];
means "mm_array is a pointer to a 5x3 array of integers". When you assign something to it, you expect that thing to be a pointer to a contiguous block of memory, which is at least big enough to contain 15 integers, or maybe an array of several such 5x3 arrays.
Suppose you didn't mention that "5" and "3".
int (*mm_array)[][]; // This is not a legal declaration in C++
Now, suppose you are handed a pointer to a newly allocated array, and we have statements like:
mm_array[1][1][1] = 2;
Or
mm_array++;
In order to know where to put the number, it needs to know where index 1 of the array is. Element 0 is easy - it's right at the pointer. But where is element 1? It's supposed to be 15 ints after that. But at compile time, you won't know that, because you didn't give the sizes. The same goes for the ++. If it doesn't know that each element of the array is 15 ints, how will it skip that many bytes?
Furthermore, when is it a 3x5 or a 5x3 array? If it needs to go to element mm_array[0][2][1], does it need to skip two rows of five elements, or two rows of three elements?
This is why it needs to know, at compile time, the size of its base array. Since the pointer has no information about sizes in it, and merely points to a contiguous block of integer, that information will need to be known in advance.
In Java, the situation is different. The array itself and its sub-arrays, are all Java objects. Each array is one-dimensional. When you have an expression like
arr3D[0][1][2]
arr3D is known to be a reference to an array. That array has length and type information, and one dimension of references. It can check whether 0 is a valid index, and dereference the 0th element, which is itself a reference to an array.
Which means that now it has type and length information again, and then a single dimension of references. It can check whether 1 is a valid index in that array. If it is, it can go to that element, and dereference it, and get the innermost array.
Since the arrays are not a contiguous block, but rather references to objects, you don't need to know sizes at compile time. Everything is allocated dynamically, and only the third level (in this case) has actual contiguous integers in it - only a single dimension, which does not require advance calculation.
I guess your real question is, why a stack array must have a fixed size at compile time.
Well, for one, that makes it easier to calculate the addresses of following local variables.
Dynamic size for stack array isn't impossible, it's just more complicated, as you would imagine.
C99 does support variable length arrays on stack. Some C++ compilers also support this feature. See also Array size at run time without dynamic allocation is allowed?
I believe this has to do with what code the compiler issues to address the array. For dynamic arrays you have an array of arrays and cells are addressed by redirecting a redirection.
But multidimensional arrays are stored in contiguous memory and the compiler indexes them using a mathematical formula to calculate the cell position based upon each of the array's dimensions.
Therefore the dimensions need to be known (declared) to the compiler (all except the last one).
Correction:
C sometimes has dimension
Java
Sometype some[];
declaration is itself an (declaration of) reference to Object and can be changed (to new instance or array). This may be one reason so in java dimension cannot be given "on the left side". Its near to
Sometype * some
in C (forgive me, array in Java is much more intelligent and safe)
if we think about pass array to C function, formal situation is similar like in Java. Not only we don't have dimension(s), but cannot have.
void func(Sometype arg[])
{
// in C totally unknown (without library / framework / convention etc)
// in Java formally not declared, can be get at runtime
}
In Java, it doesn't seem to care about array size when defining an array reference variable (it's an error in Java to explicitly provide a size),
It is not Java doesn't care about the initial array size when you define an array. The concept of an array in Java is almost totally different from C/C++.
First of all the syntax for creating an array in Java is already different.
The reason why you are still seeing C/C++ look-alike square brackets in Java when declaring arrays is because when Java was implemented, they tried to follow the syntax of C/C++ as much as possible.
From Java docs:
Like declarations for variables of other types, an array declaration has two components: the array's type and the array's name. An array's type is written as type[], where type is the data type of the contained elements; the brackets are special symbols indicating that this variable holds an array. The size of the array is not part of its type (which is why the brackets are empty)
When you declare an array in Java, for e.g.:
int[] array;
You are merely creating an object which Java called it an array (which acts like an array).
The brackets [ ] are merely symbol to indicate this is an Array object. How could you insert numbers into a specific symbol which Java uses it to create an Array Object!!
The brackets looks like what we used in C/C++ array declaration. But Java gives a different meaning to it to the syntax looks like C/C++.
Another description from Java docs:
Brackets are allowed in declarators as a nod to the tradition of C and C++.
Part of your question:
This allows me to create jagged array,which I'm not sure I can create in C++ (not arrays of pointers).
From Java Docs:
In the Java programming language, a multidimensional array is an array whose components are themselves arrays. This is unlike arrays in C or Fortran. A consequence of this is that the rows are allowed to vary in length
If you are interested to find out more on Java Arrays, visit:
here
here
and here
The difference between in arrays in C++ and Java is that Java arrays are references, like all non-primitive Java objects, while C++ arrays are not, like all C++ objects (yes, you hear a lot that C++ arrays are like pointers, but see below).
Declaring an array in C++ allocates memory for the array.
int a[2];
a[0] = 42;
a[1] = 64;
is perfectly legal. However, to allocate memory for the array you must know its size.
Declaring an array in Java does not allocate memory for the array, only for the reference, so if you do:
int[] a;
a[0] = 42;
you'll get a NullPointerException. You first have to construct the array (and also in Java, to construct the array you need to know its size):
int[] a = new int[2];
a[0] = 42;
a[1] = 64;
So what about C++ array being pointers? Well, they are pointers (because you can do pointer arithmetic with them) but they are constant pointers whose value is not actually stored in the program but known at compile time. For this reason the following C++ code will not compile:
int a[2];
int b[2];
a = b;
You're confusing the meaning of some of your C++ arrays:
e.g., your 'm_array' is a pointer to an array of values - see the following compilable C++ example:
int array_of_values[3] = { 1, 2, 3 };
int (*m_array)[3] = &array_of_values;
the equivalent Java is:
int[] array_of_values = {1, 2, 3};
int[] m_array = array_of_values;
similarly, your 'mm_array' is a pointer to an array of arrays:
int array_of_array_of_values[3][2] = { 1, 2, 3, 4, 5, 6 };
int (*mm_array)[3][2] = &array_of_array_of_values;
the equivalent Java is:
int[][] array_of_array_of_values = { {1, 2}, {3, 4}, {5, 6} };
int[][] mm_array = array_of_array_of_values;

Copy array variable to another array variable

I'd like to copy an array variable from one array to the array variable of another array. How would I do that? Is it just Array1[1] = Array2[1] ?
If you write
array1[1] = array2[1];
that will copy the value of the second element of array2 into the second element of array1. If that's all you wanted to do, that's fine.
It won't associate the two arrays together. If you then write:
array2[1] = someNewValue();
then that change won't be visible in array1.
Its simple...
array1[1] = array2[1];
But mind that these 2 are two different Array Object on the heap, change in one won't reflected in other.

Categories