Array-n't You Curious?

Olaoluwa Oke| 28 February 2024

Ever wondered how arrays work under the hood? Yes?, Welcome to Memory Hotel, your one-stop shop for understanding the inner workings of these fascinating data structures! Here, we'll ditch the dry lectures and use images to make sure this is easy to understand

Before we go ahead , let us define what an array is

an array is a container object that holds a fixed number of values of a single type. The length of an array is established when the array is created, and it remains constant throughout the array's lifetime.


An array in java is an instance of the java.lang.Array class in the java JDK which means it is indeed an object. As an object, an array can be assigned to variables, passed as arguments to methods, and returned from methods. Each array object maintains a unique identity, and multiple variables can reference the same array object.

I promise the boring part just ended , Now we will use a comic and some pictures to see what happens when you declare an array of integers with spaces for 3 elements

Now, User( the person typing the java code and initializing an array, and we assume this has been run already) Hotell attendant ( memory manager that automaticaly allocates and deallocates memory spaces for objects)



****************************************************

User: Hi there, I'd like to reserve some rooms. I need an array of integers, size 3, please.

picture goes here

Hotel Attendant:Certainly! I've prepared three rooms for you at memory address 0x7fff5fbff8c0. Here's your key:

int []A = new int[3];


(now `A` is the reference to our just created array instance , and since they're integer rooms , they already have `0`s in them, if we `System.out.println(A)` we will get the address `0x7fff5fbff8c0` )

User: Great! So, how do I access each room?

Hotel Attendant: To access each room, or index, in your array, you need to calculate the offset from the starting memory address. Since your data type is an integer, which is 4 bytes wide, you'll need to multiply the index by 4 to find the correct offset.

picture goes here

(So , if we want to input into the first array index 0 , A[0] , under the hood , it goes to the address 0x7fff5fbff8c0 and adds the element there , and if you want to add the second element at A[1] , then under the hood it does 0x7fff5fbff8c0 + 4 bytes ( size of an integer) )

User: Can you give me an example?

Hotel Attendant: Of course! Let's say you want to access the second room, which is index 1. You'd calculate the offset as follows:

Offset = Index * Size of data type
Offset = 1 * 4 bytes
Offset = 4 bytes

User: So, to access the second room, I need to go to the memory address 0x7fff5fbff8c0 and then add 4 bytes to it?

Hotel Attendant: That's right! The address for the second room would be 0x7fff5fbff8c4. Just remember, each room is 4 bytes wide, so you can find any room by calculating the correct offset.

picture goes here

User: Thanks for the explanation! I'm ready to start filling these rooms with integers.

Hotel Attendant: Just make sure that when you want to access these rooms, you have the correct key - or in programming terms, the right method to retrieve and display your data. Let's think of it as having a guest list for each room.

User: That makes sense. So, how do I get that guest list?

Hotel Attendant: There are two popular ways to retrieve and display the guests in your rooms. The first one is like having a master key - a simple method that unlocks all the rooms and shows you everything at once. In Java, this master key is called "Arrays.toString(arrayName)." It returns a string representation of the array, showing all the elements in one go.

(Now the .toString() method here is method in the java.util.Arrays package that needs to be imported , it is a method that returns a string representation of the array's elements. When you call toString() on an array, it returns a string containing the array elements enclosed in square brackets and separated by commas. not to be confused for the .toString() method of the java.lang.Objects class )


User: That sounds convenient! And the second method?

Hotel Attendant: The second method is like having individual keys for each room - you'll visit each room one by one and greet each guest personally. In programming, this is done using loops, such as a "for" loop. You iterate through each index of the array, accessing and displaying each element individually.

User: So, if I want to be more personal and interact with each guest, I should use a loop. But if I just want a quick overview of all the guests, I can use Arrays.toString().

Hotel Attendant: That's right! It's all about choosing the right method for the right situation. Just remember, whether you use a master key or individual keys, the goal is to access the rooms and interact with the guests in the way that suits you best.

User: Thanks for the helpful advice! I'll keep that in mind when working with my array.

*******************************************************************
Questions ?
Q: How does Java know where the space it allocates end , if elements are added by offsets

A : When you declare an array, the JVM calculates the memory required based on the size of the data type and the number of elements you specify. It allocates contiguous memory blocks to hold the elements of the array. Java arrays are guaranteed to be contiguous, meaning the elements are stored in adjacent memory locations. The end of the allocated space for the array is determined by the size of the array and the size of the data type. For example, if you have an array of integers (int), each integer occupies 4 bytes of memory. If you declare an array of size 3, the JVM will allocate 3 * 4 = 12 bytes of contiguous memory for storing these integers. The JVM knows where that 12 bytes end

********************************************

Next time we will talk about how This memory allocation typically happens on the heap, a region of memory used for dynamic memory allocation.

************LESSON ENDED : MORE NOTES ********************

In JavaScript, unlike Java, you have the flexibility to create an array and view it in different sizes using typed arrays and ArrayBuffers. For instance, you can create a single ArrayBuffer and view it as both a Uint8Array and a Uint16Array. (code below);

Uint8Array (a8)

In a Uint8Array, each element represents an 8-bit unsigned integer, meaning it occupies 1 byte of memory. This byte-sized representation allows you to directly access specific bytes in the buffer. For instance, a8[0] accesses the first byte, a8[1] accesses the second byte, and so forth.

Uint16Array (a16)

Uint16Array (a16): Each element in a Uint16Array represents a 16-bit unsigned integer, so it occupies 2 bytes of memory. When you're accessing elements in a Uint16Array, you need to account for the fact that each element spans 2 bytes in memory. To access the correct byte offset for each element, you need to multiply the index by 2. For example, to access the first element, you'd need to access bytes 0 and 1, for the second element, bytes 2 and 3, and so on groupinfg two 8bits (8+8 = 16).

// Create an ArrayBuffer with 8 bytes of memory
// and initialize its values using a Uint8Array and a Uint16Array view
let buffer = new ArrayBuffer(8);

// Create a Uint8Array view onto the buffer
let a8 = new Uint8Array(buffer);

// Set some values in the Uint8Array
a8[0] = 10;
a8[1] = 20;

// Access and print the values
console.log("Uint8Array values:");
console.log("a8[0]:", a8[0]); // Output: 10
console.log("a8[1]:", a8[1]); // Output: 20

// Create a Uint16Array view onto the same buffer
let a16 = new Uint16Array(buffer);

// Access and print the values
console.log("\nUint16Array values:");
console.log("a16[0]:", a16[0]); // Output: 5120 (combines a8[0] and a8[1])

This is what integers do when they get into their 4bytes room