I have done an exercise of classes and the resulting code, although it works, it is not clear to me what it does.
It's not that I don't know how to interpret it, but that I don't understand how it works internally. I expose the code and the doubt.
Make a function that receives a two-dimensional array of integers and returns another two-dimensional array with the copied elements but twice as many columns. New items are padded with zeros. Use copyOf from the Arrays class. For example, if it receives {{1 , 2},{3, 4},{5, 6}}, it returns {{1 , 2, 0, 0},{3, 4, 0, 0},{5, 6, 0, 0}}.
package arrays;
import java.util.Arrays;
public class Ejercicio6 {
public static void main(String[] args) {
// VARIABLES \\
int[][] array = { {5, 8, 8}, {7, 4}, {8, 9, 7, 2} };
int arrayTest[][];
arrayTest = fillArray(array);
System.out.println(Arrays.deepToString(arrayTest));
}
/* Recibe un array y lo devuelve con el doble de valores.
* */
public static int[][] fillArray(int[][] array) {
// VARIABLES \\
int result[][] = new int[array.length][0];
for (int i = 0; i < array.length; i++) { // Recorre la primera dimensión.
result[i] = Arrays.copyOf(array[i], array[i].length * 2);
}
return result;
}
}
Now, my doubt comes in the following lines:
int result[][] = new int[array.length][0];
Here I am creating a two dimensional array of n x 0 dimensions... I don't even know how that works.
What am I creating n memory addresses that point to nothing? What to point to a null? How is it even possible to make the second dimension have a length of 0 elements?
for (int i = 0; i < array.length; i++) { // Recorre la primera dimensión.
result[i] = Arrays.copyOf(array[i], array[i].length * 2);
}
Here it is assumed that I go through the first dimension of the array and that I create an array for each dimension that is the copy of another array but with twice the number of values, filling the remaining values... But how is it possible?
Supposedly my first dimension should bind to arrays with a length of 0 elements and by doing that, am I loading that array? and modifying the memory address?
I would appreciate if someone can explain to me what happens internally; that it works is fine, but that I have no idea why, it is not so good, in my opinion.
Thanks.
Arrays are of a defined size and cannot be modified once created. Therefore, you need to know their total length when creating them, but in your exercise you do not have this information at the beginning. Furthermore, for each line the length varies, so in the best case you would have to create N lines of length M, where M is the length of the longest line... not very efficient if you have 3 lines out of 4 elements and one of 400.
What your code does is initially create an array of N lines of length 0, to save memory and time. Then, when copying each line, it finds out its length and creates it, replacing the array of 0 elements with the final one.
You could do the same like this:
The difference is that if you try to get
result[0].length
at some point, you would get aNullPointerException
, while with the used option you would get a 0. In your particular case, since you never do this type of check, you could save the 0, which does not contribute anything.You must understand how arrays work in Java. Each array is actually an object, that is, internally the object will have a pointer in which it will refer to a memory block, where all the elements of said array will be. The object should also have another memory address in which to store the length of the array.
For example:
This line of code:
It is equivalent to this:
If you can tell, the identifier
elements
is actually an implicit pointer (I say "implicit" because there are no pointers in java, but internally), in which, it receives the base address (of the first element) of an object and in This object is where the memory register (the pointer) will be, which will store the base address of the memory block where the array data is stored.To understand this better, I'll lay it out in a memory diagram:
By default, the variable/pointer
elements
would be pointing to the base address of the blockA
(ie a0x04
). The blockA
is the object created fromnew int[]
, in which, it will have two memory addresses. At first address (0x04
) is basically the pointer, which will store the first memory address of the first element of the blockB
(that is, address0x24
) and at address0x08
is where the length of the array will be stored, which in this case is3
. The blockB
is basically where the array data will be.Understanding this, it is easy to understand how two-dimensional arrays work. Because basically two-dimensional arrays are also objects and that internally the object will have the reference of a pointer in which it will point to the base address of an array of pointers , where each pointer will point to an object of type
int[]
, where said object will have the pointer that will refer to the first element of the array.This line of code:
It is equivalent to this:
And here we demonstrate that we are actually creating an object with
new int[][]
and then3
objects of typeint[]
in which each base address of the object will be stored in an array of pointers (the reference of this array should be stored in the object created from withnew int[][]
) .To understand it better, I will translate it into a diagram:
This diagram basically indicates a representation of how the two-dimensional array will be stored in memory.
Explanation:
The block
A
is the object created fromnew int[][]
, where the variable/pointerarray
(it's the name you gave the variable) would point to the base address of that object, which in this case is the address0x04
, and the address0x08
is where the length of the block will be. two-dimensional array, in this case, would be3
(because it is the number of rows).address
0x04
is a pointer to which you will store the base address of the blockB
(in this case, it is address0x24
). Then the blockB
would be the memory block (an array of pointers) where the base addresses of each object of type will beint[]
.Those type objects
int[]
are the blocksC
,D
andE
. So the blockC
is the object (of typeint[]
) where the pointer (that is, the address0x64
) and the length of the array (the address0x72
) will be stored.The address
0x64
is the register that will have stored the first memory address of the first element of the blockF
(that is, the address0x76
). I also emphasize that the blocksF
,G
andH
are the arrays where the data of each row of the array is stored. This same analysis can be applied to the other remaining blocks (I will not explain it because it would be very redundant).So, when it is understood how a two-dimensional array actually works in MEMORY , we could give answers to these questions:
What you are creating there is an object of type
int[][]
, which internally will have a pointer that will refer to the base address of the array of objects (or array of pointers), in which it will store the base address of each object of typeint[]
, however , each object (of typeint[]
) will have a length of0
elements.This is represented in memory like this:
If you notice, it is almost the same diagram as above, the difference is that the blocks
F
,G
andH
(represent the data that each row of the matrix will have) will never be created because the length of the vector is0
. Therefore, the base address0x64
(of the blockC
) would not point to any data in the array, since no memory has been reserved for it yet.For example:
The code above would create the block
F
in memory and now the pointer (in our example it would have the address0x64
) would point to the base address of that block (which would be to the array element1
).Hmmmmmm... Not exactly. What is being created is an array of pointers which point to an object of type
int[]
, so if they point to something.No. Each element of the array of pointers will point to the first memory address of an object of type
int[]
, so they do not point tonull
.Yes. But this will depend on how you write the Java code.
For example:
If we do not write the
0
in the second bracket, we would be creating an array of pointers, where each element would point tonull
. So, when getting the length with this code:It would give us an exception (
NullPointerException
), because you would be accessing an attribute through a pointer that does not actually point to a memory address belonging to the program, therefore, in this case, you would have to be very careful. However, doing it this way avoids assigning an object of typeint[]
to each element of the pointer array and this would save memory.If you leave the , in the second dimension
0
, you would be creating an object of typeint[]
in each pointer of the array of objects and the truth is, I see it for pleasure, because, when the loop is executed, the content would be overwritten of each element of the pointer array. So the object references that were there before are lost and the garbage collector will know when to free the memory.If possible. And it makes a lot of sense. Because basically the array of pointers is created where the references of each object of type will be
int[]
. If we look at the diagram above, the only thing that is created in memory is:int[][]
.int[]
in which, each reference will be stored in the respective array of pointers.Everything is explained in the same diagram.
Everything in this life is possible, unless she loves you. Nah lie. What that code does is simple:
In each iteration, it creates an object of type
int[]
, that is, if we look at our memory diagram that we had done previously, in reality, in each iteration, the blocksF
,G
andH
that represent the data of the array, would be created.Basically what the copyOf method does is create a new array with the length you pass to it. That is, if we are in the first iteration, then the length would give as a result
3
and since it is multiplied by2
, itcopyOf
returns an array of 6 elements and since it only finds 3 data, the rest by default are0
.This is like if you did this:
If you print each element of the array to the screen, it will return
0
, because the garbage collector, when allocating memory, initializes it to ,0
and this is basically what happens with thecopyOf
.Hmmmmmmm... If you are modifying the memory register.
When doing this:
It's how you do this:
That is, what is happening in that code is that an object of type is being created
int[]
, in which, internally, the reference (the base address) of the array will be stored and from that, any element of the array can be accessed .I will gladly explain it to you, well, actually, I already explained it to you and I was exhausted.