How does length variable works internally on arrays in Java? [duplicate] - java

We can determine the length of an ArrayList<E> using its public method size(), like
ArrayList<Integer> arr = new ArrayList(10);
int size = arr.size();
Similarly we can determine the length of an Array object using the length property
String[] str = new String[10];
int size = str.length;
Whereas the size() method of ArrayList is defined inside the ArrayList class, where is this length property of Array defined?

Arrays are special objects in java, they have a simple attribute named length which is final.
There is no "class definition" of an array (you can't find it in any .class file), they're a part of the language itself.
10.7. Array Members
The members of an array type are all of the following:
The public final field length, which contains the number of components of the array. length may be positive or zero.
The public method clone, which overrides the method of the same name in class Object and throws no checked exceptions. The return type of the clone method of an array type T[] is T[].
A clone of a multidimensional array is shallow, which is to say that it creates only a single new array. Subarrays are shared.
All the members inherited from class Object; the only method of Object that is not inherited is its clone method.
Resources:
JLS - Arrays

It's "special" basically, with its own bytecode instruction: arraylength. So this method:
public static void main(String[] args) {
int x = args.length;
}
is compiled into bytecode like this:
public static void main(java.lang.String[]);
Code:
0: aload_0
1: arraylength
2: istore_1
3: return
So it's not accessed as if it were a normal field. Indeed, if you try to get it as if it were a normal field, like this, it fails:
// Fails...
Field field = args.getClass().getField("length");
System.out.println(field.get(args));
So unfortunately, the JLS description of each array type having a public final field length is somewhat misleading :(

It's defined in the Java language specification:
The members of an array type are all of the following:
The public final field length, which contains the number of components of the array. length may be positive or zero.
Since there is a limitless number of array types (for every class there is a corresponding array type, and then there are multidimensional arrays), they cannot be implemented in a class file; the JVM has to do it on the fly.

Even though this is not a direct answer to the question, it is an addition to the .length vs .size() argument. I was researching something related to this question so when I came across it I noticed that the definition(s) provided here
The public final field length, which contains the number of components of the array.
is not "exactly" correct.
The field length contains the number of available places to put a component, not the number of components present in the array. So it represents the total available memory allocated to that array, not how much of that memory is filled.
Example:
static class StuffClass {
int stuff;
StuffClass(int stuff) {
this.stuff = stuff;
}
}
public static void main(String[] args) {
int[] test = new int[5];
test[0] = 2;
test[1] = 33;
System.out.println("Length of int[]:\t" + test.length);
String[] test2 = new String[5];
test2[0] = "2";
test2[1] = "33";
System.out.println("Length of String[]:\t" + test2.length);
StuffClass[] test3 = new StuffClass[5];
test3[0] = new StuffClass(2);
test3[1] = new StuffClass(33);
System.out.println("Length of StuffClass[]:\t" + test3.length);
}
Output:
Length of int[]: 5
Length of String[]: 5
Length of StuffClass[]: 5
However, the .size() property of the ArrayList does give the number of elements in the list:
ArrayList<Integer> intsList = new ArrayList<Integer>();
System.out.println("List size:\t" + intsList.size());
intsList.add(2);
System.out.println("List size:\t" + intsList.size());
intsList.add(33);
System.out.println("List size:\t" + intsList.size());
Output:
List size: 0
List size: 1
List size: 2

it's public final field , which contains the number of components of the array (length may be positive or zero)
An array thus has the same public fields and methods as the following class:
class A implements Cloneable, java.io.Serializable {
public final int length = X;
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new InternalError(e.getMessage());
}
}
}
more info at
10.7 Array Members
http://java.sun.com/docs/books/jls/second_edition/html/arrays.doc.html

To answer it as it-is, where is this length property of array defined? In a special Object header.
Easy to see via JOL
int [] ints = new int[23];
System.out.println(ClassLayout.parseInstance(ints).toPrintable());
One of the lines from this output is going to be:
OFFSET SIZE TYPE DESCRIPTION
16 4 (object header) 17 00 00 00 (00010111 00000000 00000000 00000000) (23)
Usually Objects have two headers (mark and klass), arrays have one more that always occupy 4 bytes in length, as size is an int.

The keyword length acts like a data filed defined. When using in an array, we can use it to access how many elements in an array. Regarding to String[], we can invoke length() method defined in String class. With regard to ArrayList, we can use size() method defined in ArrayList. Note that when creating an array list with ArrayList<>(capacity), the initial size() of this array list is zero since there is no element.

Related

Different methods in JAVA [duplicate]

We can determine the length of an ArrayList<E> using its public method size(), like
ArrayList<Integer> arr = new ArrayList(10);
int size = arr.size();
Similarly we can determine the length of an Array object using the length property
String[] str = new String[10];
int size = str.length;
Whereas the size() method of ArrayList is defined inside the ArrayList class, where is this length property of Array defined?
Arrays are special objects in java, they have a simple attribute named length which is final.
There is no "class definition" of an array (you can't find it in any .class file), they're a part of the language itself.
10.7. Array Members
The members of an array type are all of the following:
The public final field length, which contains the number of components of the array. length may be positive or zero.
The public method clone, which overrides the method of the same name in class Object and throws no checked exceptions. The return type of the clone method of an array type T[] is T[].
A clone of a multidimensional array is shallow, which is to say that it creates only a single new array. Subarrays are shared.
All the members inherited from class Object; the only method of Object that is not inherited is its clone method.
Resources:
JLS - Arrays
It's "special" basically, with its own bytecode instruction: arraylength. So this method:
public static void main(String[] args) {
int x = args.length;
}
is compiled into bytecode like this:
public static void main(java.lang.String[]);
Code:
0: aload_0
1: arraylength
2: istore_1
3: return
So it's not accessed as if it were a normal field. Indeed, if you try to get it as if it were a normal field, like this, it fails:
// Fails...
Field field = args.getClass().getField("length");
System.out.println(field.get(args));
So unfortunately, the JLS description of each array type having a public final field length is somewhat misleading :(
It's defined in the Java language specification:
The members of an array type are all of the following:
The public final field length, which contains the number of components of the array. length may be positive or zero.
Since there is a limitless number of array types (for every class there is a corresponding array type, and then there are multidimensional arrays), they cannot be implemented in a class file; the JVM has to do it on the fly.
Even though this is not a direct answer to the question, it is an addition to the .length vs .size() argument. I was researching something related to this question so when I came across it I noticed that the definition(s) provided here
The public final field length, which contains the number of components of the array.
is not "exactly" correct.
The field length contains the number of available places to put a component, not the number of components present in the array. So it represents the total available memory allocated to that array, not how much of that memory is filled.
Example:
static class StuffClass {
int stuff;
StuffClass(int stuff) {
this.stuff = stuff;
}
}
public static void main(String[] args) {
int[] test = new int[5];
test[0] = 2;
test[1] = 33;
System.out.println("Length of int[]:\t" + test.length);
String[] test2 = new String[5];
test2[0] = "2";
test2[1] = "33";
System.out.println("Length of String[]:\t" + test2.length);
StuffClass[] test3 = new StuffClass[5];
test3[0] = new StuffClass(2);
test3[1] = new StuffClass(33);
System.out.println("Length of StuffClass[]:\t" + test3.length);
}
Output:
Length of int[]: 5
Length of String[]: 5
Length of StuffClass[]: 5
However, the .size() property of the ArrayList does give the number of elements in the list:
ArrayList<Integer> intsList = new ArrayList<Integer>();
System.out.println("List size:\t" + intsList.size());
intsList.add(2);
System.out.println("List size:\t" + intsList.size());
intsList.add(33);
System.out.println("List size:\t" + intsList.size());
Output:
List size: 0
List size: 1
List size: 2
it's public final field , which contains the number of components of the array (length may be positive or zero)
An array thus has the same public fields and methods as the following class:
class A implements Cloneable, java.io.Serializable {
public final int length = X;
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new InternalError(e.getMessage());
}
}
}
more info at
10.7 Array Members
http://java.sun.com/docs/books/jls/second_edition/html/arrays.doc.html
To answer it as it-is, where is this length property of array defined? In a special Object header.
Easy to see via JOL
int [] ints = new int[23];
System.out.println(ClassLayout.parseInstance(ints).toPrintable());
One of the lines from this output is going to be:
OFFSET SIZE TYPE DESCRIPTION
16 4 (object header) 17 00 00 00 (00010111 00000000 00000000 00000000) (23)
Usually Objects have two headers (mark and klass), arrays have one more that always occupy 4 bytes in length, as size is an int.
The keyword length acts like a data filed defined. When using in an array, we can use it to access how many elements in an array. Regarding to String[], we can invoke length() method defined in String class. With regard to ArrayList, we can use size() method defined in ArrayList. Note that when creating an array list with ArrayList<>(capacity), the initial size() of this array list is zero since there is no element.

Initilizing a static array within an object class in Java

I would like to have a static array in a Java class with an undetermined size initially. The intent is to use the array to store values calculated in a method in one class and used in another.
E.g. the 'TwoDX(Y)Pos[] arrays defined here:
public class DisplayObject {
// Each object is defined by a color, number of vertices, and dim (2,3,4) coordinate vertex locations
// Use dim to verify that the right number of vertices were sent
public static int Dim=3;
public static int RefDist=100;
public static int TwoDXpos[];
public static int TwoDYpos[];
}
And used here:
public void render2D(){
for (int cnt=0; cnt<this.NoOfVerts; cnt++){
if (this.coords[cnt*Dim+2] < RefDist) {break;}
TwoDXpos[cnt]=this.coords[cnt*Dim]/(this.coords[cnt*Dim+2]/RefDist);
TwoDYpos[cnt]=this.coords[cnt*Dim+1]/(this.coords[cnt*Dim+2]/RefDist);
}
}
But, since the original static references have no defined size, they reference Null pointers at execution.
How would you create such arrays?
I would like to have a static array in a java class with an initially undetermined size.
Sorry.
That isn't possible in Java. JLS-10.3. Array Creation says (in part)
The array's length is available as a final instance variable length.
Alternative
However, you could have a List of Foo(s) like
List<Foo> al = new ArrayList<>();
Use ArrayList instead of arrays.
Your code should look like this:
public class DisplayObject {
// Each object is defined by a color, number of vertices, and dim (2,3,4) coordinate vertex locations
// Use dim to verify that the right number of vertices were sent
public static int Dim=3;
public static int RefDist=100;
public static ArrayList<Integer> TwoDXPos;
public static ArrayList<Integer> TwoDYPos;
}
and the render 2d method:
public void render2D(){
for (int cnt=0; cnt<this.NoOfVerts; cnt++){
if (this.coords[cnt*Dim+2] < RefDist) {break;}
TwoDXpos.get(cnt)=this.coords[cnt*Dim]/(this.coords[cnt*Dim+2]/RefDist);
TwoDYpos.get(cnt)=this.coords[cnt*Dim+1]/(this.coords[cnt*Dim+2]/RefDist);
}
}
The advantage of using ArrayList is that you can use its add(item) method to change its size dynamically.
Hope it helps!
public void render2D() {
TwoDXpos = new int[this.NoOfVerts];
TwoDYpos = new int[this.NoOfVerts];
for (int cnt = 0; cnt < this.NoOfVerts; cnt++) {
if (this.coords[cnt * Dim + 2] < RefDist) {
break;
}
TwoDXpos[cnt] = this.coords[cnt * Dim] / (this.coords[cnt * Dim + 2] / RefDist);
TwoDYpos[cnt] = this.coords[cnt * Dim + 1] / (this.coords[cnt * Dim + 2] / RefDist);
}
}
and pls following Java naming rules to name your variable: http://www.iwombat.com/standards/JavaStyleGuide.html#Attribute%20and%20Local%20Variable%20Names
Short answer is you need to initialize the array before using them.
To avoid memory leakage, you should set its size at initialization. e.g.10.
public static int TwoDXpos[] = new int[10];
public static int TwoDYpos[] = new int[10];
If the array size changes, you should use ArrayList because its size is automatically managed by JVM
You can't use an array whose size is not determined. You should initialize the array size before method render2D() called. May be you could use this.NoOfVerts as the array size.
If you are going to use an array, you should initialize it by mentioning the size of the array in order to allocate memory before using it.
public static int TwoDXpos[];
public static int TwoDYpos[];
Any access on this would throw NullPointerException because the memory for this not allocated and object defintion has not happened at all.
You ought to remember this on array (or any objects for that sake) "Initialize before you access/use them"
If you worry is about that you are not sure about the number of elements upfront, you should use utilities like ArrayList which is provided in Java Collection Framework. This would take care dynamically adjusting the size as the number of elements increases.
Alternative Approach
private static List<Integer> twoDXPos = new ArrayList<Integer>();
private static List<Integer> twoDYPos = new ArrayList<Integer>();
and then itemes can be added using add method in java.util.Collection class. (Refer the link I gave above)
twoDXPos.add(1) //1 is an example integer here to illustrate
twoDYPos.add(1) //1 is an example integer here to illustrate

Java Reflection - Editing Array Length

I was wondering if it is possible to change to change the length of a class's integer array using the Java Reflection API. If so, how?
Nope; an array is created with a fixed length.
What you can do is get close by modifying the value of the field with a copy in larger array (using Arrays.copyOf), so long as you know modifying like this won't cause any inconsistency.
/* desired length */
final int desired = ...;
/* the instance of the object containing the int[] field */
final Object inst = ...;
/* the handle to the int[] field */
final Field field = ...;
field.set(inst, Arrays.copyOf((int[]) field.get(inst), desired));
I don't think it's possible to change array length even with Reflection.
This is a reference from java tutorial.
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. After creation, its length is fixed.
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
An array is a fixed length data structure, so there is no way that it's length will be modified. Nevertheless, one can create a new array with a new fixed length in such way it can accommodate new members using
System.arrayCopy()
It is like you have an array of type T with the size of 2,
T[] t1 = new T[2]
and it is length is fixed with 2. So it can not store any more than 2 elements. But by creating new array with a new fixed length, say 5,
T[] t2 = new T[5]
So it can accommodate 5 elements now. Now copy the contents of the t1 to t2 using
System.arraycopy(Object src, int srcPos, Object dest, int destPos, int
length)
in this case of the example,
System.arraycopy(t1, 0, t2, 0, t1.length)
Now in the new array, you have position
from t1.length to t2.length-1
is available for you to use.
I guess java will not allow you to change array length but yes you can set value at index using reflection.
import java.lang.reflect.*;
public class array1 {
public static void main(String args[])
{
try {
Class cls = Class.forName(
"java.lang.String");
Object arr = Array.newInstance(cls, 10);
Array.set(arr, 5, "this is a test");
String s = (String)Array.get(arr, 5);
System.out.println(s);
}
catch (Throwable e) {
System.err.println(e);
}
}
}

Java: Generic Static Multidimensional Arrays

If it is possible, how can I create a static multidimensional array in Java with different primitive datatypes per dimension?
By static, I mean the primitive array that is not dynamic like an ArrayList would be.
You can't.
A multidimensional array is, by definition, an array of arrays of arrays .... of something. So there's no way for any of those dimensions except the last to be anything other than an array. At least, by the traditional definition anyway. But if you mean something else by "multidimensional array", you'll need to tell us what that is.
As for "static", that is a heavily overloaded word in programming and every language that I can think of uses it to mean something slightly different. In Java, static means "belongs to a class, rather than to instances of that class." Again, if you mean something else by "static" here, you'll need to tell us what that is.
Edit: As originally posted, the question didn't include the word "primitive". That changes it a bit. Indeed, I agree that it would be nice from a convenience standpoint if Java allowed arrays to be indexed by char or even an enum rather than just int. But it doesn't.
Dimensions in an Array are always from type int. Think about it!
int a = 4;
int b = 5;
Shoe shoe = new Shoe (Color.RED, 42, "Leather");
Hat hat = new Hat (17, Color.Black);
Foo foo = foos[a][b];
Zilch pop = bars[shoe][hat]; // no go
If you have a multidimensional array of Foos, the first dimension is an Foo, the second an array of Foos, the third an array of array of Foo. The only variable type is the one at the bottom.
Edit after update of question:
Arrays aren't called static or primitive. Their size is fixed on initialization, and what they have in common with primitives is, that they are a buildin, which is threated special in some cases. They are - in contrast to the so called primitive types, which aren't that primitive (they have, for example, operators, exclusively for their own, like * / -) but meanwhile they are objects, but not declared in the library.
Call them build in-types.
Using Bhesh Gurung's trick:
Object[] arr = {new Integer[]{}, new String[]{}, new Double[]{}};
is begging for trouble, and it is not made of different datatypes per dimension. Let's start with the dimensions:
// One-dimensional object:
JPanel [] panels = new JPanel [3];
// Two-dimensional object:
JPanel [][] panels = new JPanel [3][10];
You have JPanels on the bottom level, and an Array of JPanel on the next dimension. You can add more dimension, and will always get an additional (Array of ...) wrapped around.
You can not mix different datatypes in an Array like int and char, or JPanel and JFrame, or int and JButton. Only if you abstract over the difference, and use an JComponent for JPanel and JFrame as common parent, but this will not work for the build-in types int, char, boolean and so on, because they aren't objects.
But can't you use autoboxing, and use Integer instead of int, Character instead of char, and then use Object as common parent class? Yes, you could, but then you're not using the primitives any more, and you're begging for troubles.
Dan is talking about a different thing - using differnt types for indexing in the multi-dimensional array:
byte b = 120;
short s = 1000;
String o [][] = new String[b][s];
b = 7;
s = 9;
o[b][s] = "foobar";
String foo = o[b][s];
There is no problem using bytes or shorts, but you can't restrict the size of an Array by declaring it as byte or short. In most cases the boundaries of a build-in integer type will not fit to a datatype (think 365 days per year), especially, since all types might get negative, so bounds-checking is necessary although and can't be restricted to compile time.
But now to the trouble:
We could declare the array as two-dimensional from the beginning:
Object[][] ar2 = {
new Integer [] {4, 5, 6},
new String [] {"me", "and", "you"},
new Character [] {'x', 'y', 'z'}};
That works fine, and makes the inner arrays accessible immediately without casting. But it is only known for the compiler, that the elements are Object arrays - the underlying type is abstracted away, and so we can write:
ar2[1][1] = 17; // expected: String
ar2[2][0] = "double you"; // expected: Char
This will compile flawlessly, but you're shooting yourself in the foot and get a Runtime exception for free.
Here is the source as a whole:
public class ArrOfMixedArr
{
public static void main (String args[])
{
Object[] arr = {
new Integer [] {1, 2, 3},
new String [] {"you", "and", "me"},
new Character [] {'a', 'b', 'c'}};
show (arr);
byte b = 7;
short s = 9;
String o [][] = new String[200][1000];
o[b][s] = "foobar";
String foo = o[b][s];
Object[][] ar2 = {
new Integer [] {4, 5, 6},
new String [] {"me", "and", "you"},
new Character [] {'x', 'y', 'z'}};
show (ar2);
// exeptions:
ar2[1][1] = 17; // expected: String
ar2[2][0] = "double you"; // expected: Char
}
public static void show (Object[] arr)
{
for (Object o : arr)
{
if (o instanceof Object[])
show ((Object[]) o);
else
System.out.print (o.toString () + "\t");
}
System.out.println ();
}
}
Now what is the solution?
If your base-types arrays of (int, byte, char, String, JPanel, ...) are of equal length, then you have something like a hidden Object, a database-row. Use a class instead:
class Shoe {
byte size;
String manufactor;
java.math.BigDecimal price;
java.awt.Color color;
}
Shoe [] shoes = new Shoe [7];
If you don't have different types of the same size, they might be unrelated, and should not be put in a common container.
After some testing, I have a simple solution:
Object [][] array = new Object [10][2];
array[0][0] = 2;
array[0][1] = false;
Well, you could define an array of an array of ... an array of Objects (nested with as many levels as dimensions) and at the bottom level fill each array with a different type ... and then, when you need to extract a value, cast it to the appropriate type. Too much work for what is worth, really. Java is no good for this kind of things, being a statically-typed language.
Maybe you should reconsider, why would you need such a data structure.
You can get the effect by using an object array:
final static Object tryit[][] = {
{'a',4},
{'b',7},
{'c',8},
};
#Test
public void accessArray( ) {
for (int i = 0; i < tryit.length ; i++) {
char letter = (Character)tryit[i][0];
int value = (Integer)tryit[i][1];
System.out.println(letter + " has value " + value);
}
}
The "#Test" is JUnit annnotation.
Note this approach would be subject to NullPointer and ClassCast exceptions at runtime if the wrong data is entered in the array.

varargs and the '...' argument

Consider the method declaration:
String.format(String, Object ...)
The Object ... argument is just a reference to an array of Objects. Is there a way to use this method with a reference to an actual Object array? If I pass in an Object array to the ... argument - will the resultant argument value be a two-dimensional array - because an Object[] is itself an Object:
Object[] params = ....; // Make the array (for example based on user-input)
String s = String.format("%S has %.2f euros", params);
So the first component of the array (Which is used in the String.format method), will be an array and he will generate:
[class.getName() + "#" + Integer.toHexString(hashCode())]
and then an error because the array size is 1.
The bold sequence is the real question.
This is a second question: Does a ... array/parameter have a name?
From the docs on varargs:
The three periods after the final
parameter's type indicate that the
final argument may be passed as an
array or as a sequence of arguments.
So you can pass multiple arguments or an array.
The following works just fine:
class VarargTest {
public static void main(String[] args) {
Object[] params = {"x", 1.2345f};
String s = String.format("%s is %.2f", params);
System.out.println(s); // Output is: x is 1.23
}
}
You can just pass an array:
public void foo(String... args) {
}
String args[] = new String[10];
foo(args);
The situation you are describing is going to be fairly rare: most of the time, your varargs items will be Strings, or numbers, or Widgets... it will be unusual for them to be Objects (which could be anything) or arrays.
But if the varargs argument is a bunch of Objects or an array type, then your question does arise: you can pass it a single array and then how will the compiler know whether you meant to pass an array (the one you provided), or an series of 1 item which it should PUT into an array for you?
A quick test shows the answer:
public class TestClass {
public static void main(String[] args) {
Object anObject = new Object();
Object[] anArray = new Object[] {anObject, anObject};
System.out.println("object1 = " + anObject);
System.out.println("array1 = " + anArray);
takesArgs();
takesArgs(anObject, anObject);
takesArgs(anArray); // is this the same as array1?
takesArgs(anArray, anArray);
}
public static void takesArgs(Object... stuff) {
System.out.println("The array was " + stuff);
}
}
The result of executing (your exact numbers will vary:
object1 = java.lang.Object#3e25a5
array1 = [Ljava.lang.Object;#19821f
The array was [Ljava.lang.Object;#addbf1
The array was [Ljava.lang.Object;#42e816
The array was [Ljava.lang.Object;#19821f
The array was [Ljava.lang.Object;#9304b1
So the answer is that in ambiguous cases it treats what you passed as the array instead of creating a new array to wrap it. This makes sense as you could always wrap it in an array yourself if you wanted the other interpretation.

Categories