What is inside the code for array.length () in Java?

What is stored in the 10th place of the array say

int[] array=new int[10]; 

Let's say that we have values ​​stored from array[0] to array[9] , if I were to print elements without using

 array.length() 

or for (int a: array)

How do I proceed?

My main question is how does the JVM determine the end of the array, is it when a column with a syntax state is encountered, or when is a garbage value encountered? What is the built-in code of the array.length() function?

+3
source share
9 answers

Arrays are objects with a length field. During the loop, Java loads the length field and compares the iterator with it.

See 10.7 array members in JLS

+4
source

What is stored in the 10th place of the array ... my main question is how does the JVM determine the end of the array, is it when the column is parsed or when the garbage value is encountered? What is the built-in code of the array.length () function?

Welcome C / C ++ Programmer :-)

Java uses a different paradigm than C / C ++ for arrays. C / C ++ uses the terminator / sentinel aka "garbage" value), for example NULL, to indicate the end of the array. In Java, arrays are more like objects with a special variable of type "instance variable" length , which indicates how many slots are in the array. This special "instance variable" is set when the array is created and is read-only. Its accessible by saying .length array.

Java expects the code to know when to stop at the end of the array, making sure they don't specify an index greater than length - 1 . However, the JVM checks every access to the array for security reasons, just in case. If the JVM detects an index of an array that is less than 0 or greater than length - 1 , then the JVM throws an IndexOutOfBoundsException .

What is stored in the 10th place of the array

Since we can always check the length, there is no need for a marker at the end of the array in Java. After the last element of the array, there is nothing special (probably it will be another variable memory).

if I were to print elements without using array.length()

 for(int a: array) { // code of loop body here } 

This code is magically converted by the compiler to:

 for (int i = 0; i < array.length; i++) { int a = array[i]; // code of loop body here } 

However, index variable i not available for user code. This code still uses array.length implicitly.

+4
source

Internally, the JVM can track the length of an array, but it sees fit. Actually there is a bytecode command called arraylength which the Java compiler emits when you try to get the length of the array, indicating that it is before the JVM to determine the best way to track the length of the array.

Most implementations probably store arrays as a block of memory, whose first record is the length of the array, and the rest of the elements are the actual values ​​of the array. This allows the implementation to request the length of the array along with any value in the array in O (1). However, if the implementation were to be executed, it could store elements that would be followed, for example, by the sentinel value (as you expected), but I do not believe that any implementations do this because the cost of finding the length will be linear in the size of the array .

How the foreach loop works, the compiler translates this code into something like this:

 for (int i = 0; i < arr.length; ++i) { T arrayElem = arr[i]; /* ... do work here ... */ } 

And finally, as for the 10th element of an array of 10 elements, there is no guarantee that even the object is in this place. The JVM can easily allocate space for an array so that there is no tenth element. Since you can never get this value in Java (it will throw an exception if you try), there is no requirement that the JVM even have something meaningful there.

Hope this helps!

+2
source

Determine what the “cost of garbage” is. (Hint: since everything is binary, there is no such thing unless you use the sentinel value, and this is just bad practice).

The length of the array is stored inside the Array instance as a member variable. This is nothing complicated.

+1
source

Ok, here I go :-)

Ways to Work with Arrays in C

There are many ways to deal with an array in C. For the rest, I will talk about string* (and use the strings variable, which is of type string* ). This is because t[] "effectively decomposes" into t* , and char* is the string type "C". Thus, string* is a pointer to the string "C". This glosses over a number of pedantic issues in C wrt “arrays” and “pointers”. (Remember: only because a pointer can be obtained since p[i] does not make the type an array in C.)

Now strings (of type string* ) are not able to find out its size - it represents only a pointer to a string or, possibly, NULL. Now let's look at some of the ways we can “know” size:

Use the sentinel value. In this, I assume that the NULL value is used as the watchdog value (or it could be -1 for the "array" of integers, etc.). Remember that C does not have such a requirement that arrays have a sentinel value, so this approach, like the next two, is just a convention.

 string* p; for (p = strings; p != NULL; p++) { doStuff(*p); } 

Track the size of the array from the outside.

 void display(int count, string* strings) { for (int i = 0; i < count; i++) { doStuff(strings[i]); } } 

Bind the array and length together.

 struct mystrarray_t { int size; string* strings; } void display(struct mystrarray_t arr) { for (int i = 0; i < arr.size i++) { doStuff(arr.strings[i]); } } 

Java uses this last approach.

Each array object in Java has a fixed size, which can be accessed as arr.length . There is a special mask of byte code for this work (arrays are very magical in Java), but at the language level it is displayed as just a read-only integer that never changes (remember that each array object has a fixed size), Compilers and JVM / JIT can use this fact to optimize the loop.

Unlike C, Java ensures that attempting to access the index outside the bounds will throw an exception (for performance reasons, even if it was not found, this would require the JVM to track the length of each array). In C, this is just undefined behavior. For example, if the control value was not in the object (read "required available memory"), then example # 1 would lead to a buffer overflow.

However, there is nothing to prevent the use of sentinel values ​​in Java . Unlike form C with a sentinel value, it is also safe from IndexOutOfBoundExceptions (IOOB) because the length limit is the limit. Sentinel is just early.

 // So we can add up to 2 extra names later String names[] = { "Fred", "Barney", null, null }; // This uses a sentinel *and* is free of an over-run or IOB Exception for (String n : names) { if (n == null) { break; } doStuff(n); } 

Or perhaps allow an IOOB exception, because we are doing something stupid, how to ignore the fact that arrays know their length: (See wrt "performance" comments).

 // -- THERE IS NO EFFECTIVE PERFORMANCE GAIN -- // Can ONLY add 1 more name since sentinel now required to // cleanly detect termination condition. // Unlike C the behavior is still well-defined, just ill-behaving. String names[] = { "Fred", "Barney", null, null }; for (int i = 0;; i++) { String n = strings[i]; if (n == null) { break; } doStuff(n); } 

On the other hand, I would refuse to use such primitive code - it is better to just use the appropriate data type, such as List, in almost all cases.

Happy coding.

+1
source

In a comment on another OP writes:

I agree array.length is a regular method, I was looking for any other option, if available.

There is no other reasonable implementation option open to a JVM implementation ... on any underlying hardware architecture.

In particular, the sentinel approach ONLY detects the case where the application retrieves the index of an element of an array element beyond the end.

  • If he selects 2 or more indexes outside, he will skip the watch and continue accessing memory whose contents are unknown.
  • If it is stored, the watch will not be consulted.
  • If he needs to directly access the size of the array as part of the application algorithm, searching for a clock mechanism is a very inefficient way to execute it. (Not to mention unreliability, for example, if null is a valid array element.)
  • Sentinels do not work for (most) primitive arrays, because there is no value that can be used as a sentinel. (The idea of ​​a primitive array containing null is pointless from the JLS point of view, since null not compatible with the Java primitive type.)
  • The garbage collector must have an array length in all cases.

In short, the length must be stored in an array in order to deal with other cases. Storing a sentinel device also means that you are wasting space storing redundant information, and CPU cycles create a sentinel and copy it (in the GC).

+1
source

how you will print elements without using array.length or foreach loop

Of course, you can go through the array without checking the boundaries, and then end (and internalize) the ArrayIndexOutOfBoundsException at the end:

 try { int i = 0; while (true) { System.out.println(arr[i++]); } catch (ArrayIndexOutOfBoundsException e) { // so we are past the last array element... } 

It technically works, but it's bad practice. You should not use exceptions to control flow.

0
source

From the point of view of how you would print all the elements in the array without using either for each loop or for the length field, quite honestly, you simply would not do that. You could just have a for loop, as shown below:

 try { for(int i=0 ; ; i++) { System.out.println(arr[i]); } } catch(IndexOutOfBoundsException ex) {} 

But this is a terrible way to do something!

0
source

Access to the array outside the interval [0, 9] gives an ArrayIndexOutOfBoundsException , and not just position 10. So, conceptually, you could say that all your memory (reaching indexes from Integer.MIN_VALUE to Integer.MAX_VALUE ) is filled with sentinel values, in addition to space the array itself, and when reading or writing to a position filled with a sentinel, you get your exception. (And each array has its own whole memory to spend). Of course, in fact, no one has solid memory for each array, so the VM implements access to the array a little smarter. You can imagine something like this:

 class Array<X> { private final int length; private final Class<X> componentType; /** * invoked on new X[len] . */ public Array<X>(int len, Class<X> type) { if(len < 0) { throw new NegativeArraySizeException("too small: " + len); } this.componentType = type; this.len = len; // TODO: allocate the memory // initialize elements: for (int i = 0; i < len; i++) { setElement(i, null); } } /** * invoked on a.length */ public int length() { return length; } /** * invoked on a[i] */ public X getElement(int index) { if(index < 0 || length <= index) throw new ArrayIndexOutOfBoundsException("out of bounds: " + index); // TODO: do the real memory access return ...; } /** * invoked on a[i] = x */ public X setElement(int index, X value) { if(index < 0 || length <= index) { throw new ArrayIndexOutOfBoundsException("out of bounds: " + index); } if(!componentType.isInstance(value)) { throw new ArrayStoreException("value " + value + " is of type " + value.getClass().getName() + ", but should be of type " + componentType.getName() + "!"); } // TODO: do the real memory access return value; } } 

Of course, for primitive values, checking the type of a component is a little easier, since the compiler (and then the VM byte-code verifier) ​​checks the validity of the types, sometimes making type conversions. (And initialization will be with the default value for the type, not null.)

0
source

Source: https://habr.com/ru/post/1338714/


All Articles