I understand an array object in Java is created when I call its constructor with the new keyword:
int[] myIntArray = new int[3];
But if I instead write
int[] myIntArray = {1,2,3};
an array object gets created, but I haven't called its constructor with new. How does this work under the hood - how can an object be created in Java without calling the constructor?
As far as creating the array object is concerned, it's syntactic sugar. When compiled, it works exactly like the standard syntax.
The difference here though is that with the first version, you aren't populating the array - all elements are the default value for int, which is zero.
With the second version, you're creating, and populating the array.
This part:
{1,2,3}
is an array initializer that can be used as part of a declaration. To quote the JLS, section 10.6:
An array initializer may be specified in a declaration (§8.3, §9.3,
§14.4), or as part of an array creation expression (§15.10), to create
an array and provide some initial values.
ArrayInitializer:
{ VariableInitializersopt ,opt }
The first version populates an integer array with the default 0 value. The second assigns values explicitly.
The first version is equivalent to
int[] myIntArray = {0, 0, 0};
while the second is the same as
int[] myIntArray = new int[] {1,2,3};
The new keyword is only mandatory for non declarative statements, for example .
int[] myIntArray;
myIntArray = new int[] {1,2,3};
Datatypes
Arrays
Both statements are same. The second statement int[] myIntArray = {1,2,3}; is short cut to syntax using new method.
int[] myIntArray ={1,2,3} , this case length of the array is determined by the number of values provided between braces and separated by commas.
Take this code and compile it:
public class ArrayTest {
public static void main1() {
int[] array = new int[3]; array[0] = 10; array[1] = 20; array[3] = 30;
}
public static void main2() {
int[] array = new int[] {10, 20, 30};
}
public static void main3() {
int[] array = {10, 20, 30};
}
}
Then use javap -c to disassemble it to view its bytecode to get the following results. But what you will is that the later two snippets or methods compile to the same bytecode. So int[] array = new int[] {1, 2, 3} and int[] array = {1, 2, 3} are the same. But seperately creating an array and assigning values to each of its element is treated differently and so the later two snippets are not syntactic sugar for the first snippet.
$ javap -c ArrayTest
Compiled from "ArrayTest.java"
public class ArrayTest extends java.lang.Object{
public ArrayTest();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main1();
Code:
0: iconst_3
1: newarray int
3: astore_0
4: aload_0
5: iconst_0
6: bipush 10
8: iastore
9: aload_0
10: iconst_1
11: bipush 20
13: iastore
14: aload_0
15: iconst_3
16: bipush 30
18: iastore
19: return
public static void main2();
Code:
0: iconst_3
1: newarray int
3: dup
4: iconst_0
5: bipush 10
7: iastore
8: dup
9: iconst_1
10: bipush 20
12: iastore
13: dup
14: iconst_2
15: bipush 30
17: iastore
18: astore_0
19: return
public static void main3();
Code:
0: iconst_3
1: newarray int
3: dup
4: iconst_0
5: bipush 10
7: iastore
8: dup
9: iconst_1
10: bipush 20
12: iastore
13: dup
14: iconst_2
15: bipush 30
17: iastore
18: astore_0
19: return
Under the hood, both ways of initializing an array is the same.
For another example, look at this:
String str = "Hello"; // no 'new' statement here
String str = new String("Hello");
Both statements do the same thing, but one is far more convenient than the other. But under the hood, they pretty much do the same thing after compilation.
Related
I have a question that i have been pondering for a while. Take for instance this particular piece of class
class A{
private static ArrayList<String> listOne;
public Static ArrayList<String> getList()
{
return this.listOne
}
}
Let say i have class B that possess a method to read the details with listOne. To Look through the arraylist, i would need to first get the size of the list in order for my code to know when the arraylist ends. There are 2 ways in which i can do so, one being
int listSize = A.getList().size()
for(int count =0; count < listSize; count++)
{
// code to read through arraylist
}
or i can achieve the same thing with
for(int count=0; count < A.getList().size(); count++)
{
// code to read through arraylist
}
In terms of memory and efficiency, which method is better? Furthermore let says i am reading through a very large array recursively. For simplicity purposes, lets assume that recursively reading through this array would a stack overflow exception. In this situation, would the first method theoretically cause a stack overflow to happen earlier then the second method seeing that each recursive call's stack frame has to keep the state of the variable "listSize"?
Have a look at the result of javap -verbose:
0: invokestatic #2 // Method A.getList:()Ljava/util/ArrayList;
3: invokevirtual #3 // Method java/util/ArrayList.size:()I
6: istore_1
7: iconst_0
8: istore_2
9: iload_2
10: iload_1
11: if_icmpge 27
14: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
17: iload_2
18: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
21: iinc 2, 1
24: goto 9
27: iconst_0
28: istore_2
29: iload_2
30: invokestatic #2 // Method A.getList:()Ljava/util/ArrayList;
33: invokevirtual #3 // Method java/util/ArrayList.size:()I
36: if_icmpge 52
39: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
42: iload_2
43: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
46: iinc 2, 1
49: goto 29
52: return
First case is:
9: iload_2
10: iload_1
11: if_icmpge 27
14: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
17: iload_2
18: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
21: iinc 2, 1
24: goto 9
And the second one:
29: iload_2
30: invokestatic #2 // Method A.getList:()Ljava/util/ArrayList;
33: invokevirtual #3 // Method java/util/ArrayList.size:()I
36: if_icmpge 52
39: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
42: iload_2
43: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
46: iinc 2, 1
49: goto 29
As you can see, it will get the list and its size during each loop iteration.
But, this might be optimized by JIT, so the result is not obvious from just the compiled bytecode.
Created from:
import java.io.*;
import java.util.*;
public class Z {
public static void main(String[] args) throws Exception {
int listSize = A.getList().size();
for(int count =0; count < listSize; count++) {
System.out.println(count);
}
for(int count =0; count < A.getList().size(); count++) {
System.out.println(count);
}
}
}
class A{
private static ArrayList<String> listOne = new ArrayList<>(Arrays.asList("1", "2", "3"));
public static ArrayList<String> getList()
{
return listOne;
}
}
Both the loop are same. Second one is better coding as it reduces line of code.
Since you mentioned that your need is to traverse the list it is much better to use the enhanced (for-each) for loop.
What are the Advantages of Enhanced for loop and Iterator in Java?
why is enhanced for loop efficient than normal for loop
Regarding which of the method is more efficient, I think they won't have any noticeable differences. And depending on the JVM, like Germann has said, the compiler will even optimize this. So just don't worry about this negligible difference.
I personally will use the second method since it has fewer lines of code and I'm lazy...
However, why not use neither?
There's a super cool alternative, and its name is... JON CENA The enhanced for loop.
Let's compare it with a normal for loop:
Normal:
for (int i = 0 ; i < A.getList().size() ; i++ {
}
Enhanced:
for (String item : A.getList()) {
// Instead of using A.getList().get(i) to access the items, just use "item"!
}
Look how nice it is!
The major difference between these two for loops is that
The normal for loop is just a kind of a while loop with initialization and incrementation.
The enhanced for loop calls .iterator().hasNext() and .iterator().next() to loop.
You need to know the size of the list to use a normal for loop
Your list just needs to implement Iterable and probably Iterator to use an enhanced for loop. No size is needed.
An enhanced for loop has the following limitations:
You can't loop through two arrays at the same time
It's better to use a normal for loop if you want to know the index of the list, since calling indexOf a lot of times is not very efficient.
I'm having a problem initializing array of HashSet
int N = 100;
HashSet<Integer> []array = new HashSet[N];
for (HashSet<Integer> set:array){
set = new HashSet<Integer>();
}
But the array contains only null. (Also error when HashSet []array = .... )
But when running with:
for(int i = 0; i < N; i++){
array[i] = new HashSet<Integer>();
}
All is well.
Why does the first code isn't working? Is it my mistake?
Thank you
You never actually assign initialized instances to elements of the array. Instead you iterate over the elements of the array with a variable that gets assigned to a new object in your loop, then is never used. In a case like this the enhanced for...each syntax is not appropriate, use the traditional for loop instead.
two 'for' is different in Java, look the java code & bytecode ..
Example:
public class T{
public static void main(String[] args){
String[] data = new String[10];
System.out.print("");
for(String str:data){
str="1";
}
System.out.print("");
for(int i=0;i<data.length;i++){
data[i]="1";
}
}
}
$>javac -classpath . T.java
$>javap -c T
Compiled from "T.java"
public class T extends java.lang.Object{
public T();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: bipush 10
2: anewarray #2; //class java/lang/String
5: astore_1
6: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
9: ldc #4; //String
11: invokevirtual #5; //Method java/io/PrintStream.print:(Ljava/lang/String;)V
14: aload_1
15: astore_2
16: aload_2
17: arraylength
18: istore_3
19: iconst_0
20: istore 4
22: iload 4
24: iload_3
25: if_icmpge 44
28: aload_2
29: iload 4
31: aaload
32: astore 5
34: ldc #6; //String 1
36: astore 5
38: iinc 4, 1
41: goto 22
44: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
47: ldc #4; //String
49: invokevirtual #5; //Method java/io/PrintStream.print:(Ljava/lang/String;)V
52: iconst_0
53: istore_2
54: iload_2
55: aload_1
56: arraylength
57: if_icmpge 71
60: aload_1
61: iload_2
62: ldc #6; //String 1
64: aastore
65: iinc 2, 1
68: goto 54
71: return
}
from line 25--44 and line 57--71:
aload : Retrieves an object reference from a local variable and pushes it onto the operand stack.
aaload : Retrieves an object reference from an array of objects and places it on the stack.
astore : Take object or reference store to local variable.
aastore : Take reference type value store to array.
so,first can't store array , didn't using initializing array.
An enhanced for loop, does not use the actual instances in the array( and as well, collection), but rather copies them in the loop control variable.
This should not be a problem with non-null values, since they point to the same object. Problems arise, if the values are null, and re-assigning values to the control variable, would not change the actual value. So in this case, always use regular for loops.
The same would be true, to arrays of primitive types, since coping them, and changing the copied variable, will not affect the original variable.
Simply use new Set[n] instead of new HashSet[n] , to get it working
Set<Integer>[] list = new Set[n];
for(int i=0;i<n;i++)
list[i] = new HashSet<>();
You need to create an array that contains HashSet
so, you need to initialize the array and then initialize the HashSet
which I have provided in the below code
int N = 100;
Set<Integer>[] array = new Set[n];
for(int i = 0; i < n; i++) {
array[i] = new HashSet<Integer>();
}
Can some one explain me how the internal behavior when we add two Integer objects in java? (like it is unbox Object into primitives and then add two integers and finally boxed it in to Integer object)
Integer sum = new Integer(2) + new Integer(4);
It's compiled into this:
Integer sum = Integer.valueOf(new Integer(2).intValue()+new Integer(4).intValue());
You can verify this by looking at the byte code disassembly obtained with javap -c.
Here is the part that corresponds to new Integer(2).intValue(), leaving int 2 on the stack:
0: new #2; //class java/lang/Integer
3: dup
4: iconst_2
5: invokespecial #3; //Method java/lang/Integer."<init>":(I)V
8: invokevirtual #4; //Method java/lang/Integer.intValue:()I
Here is the part that corresponds to new Integer(4).intValue(), leaving int 4 on the stack:
11: new #2; //class java/lang/Integer
14: dup
15: iconst_4
16: invokespecial #3; //Method java/lang/Integer."<init>":(I)V
19: invokevirtual #4; //Method java/lang/Integer.intValue:()I
And here the sum 2+4 is calculated with iadd, the sum is boxed into an Integer by a call to Integer.valueOf, and the result is stored in the first local variable (astore_1):
22: iadd
23: invokestatic #5; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
26: astore_1
creation of two Integer instances.
Auto-unboxing of those two instances.
new int that holds the result.
Auto-boxing the result into Integer sum instance.
Why i get this error while compiling the Java file in J2ME.
Is it because extensive use of array Objects since i have a lots of array Objects defined in the Java file ?
It might be an array initializer within a method, as in:
void someMethod() {
int[] array = {0, 1, 2, 3};
}
This is equivalent to:
int[] array = new int[4];
array[0] = 0;
array[1] = 1;
array[2] = 2;
array[3] = 3;
and each element assignment takes four VM instructions (between 4 and 12 bytes of code per element.)
If the initializer is too long, it will exceed the 32K limit on the length of a method.
There is restriction with 32KB with method code, note that not with class file size.
Simple code
public void foo() {
int arr[] = {1, 2, 3};
}
will turn into [used javap to obtain this result]
public void foo();
Code:
0: iconst_3
1: newarray int
3: dup
4: iconst_0
5: iconst_1
6: iastore
7: dup
8: iconst_1
9: iconst_2
10: iastore
11: dup
12: iconst_2
13: iconst_3
14: iastore
15: astore_1
16: return
So you can imagine your huge & ocmplex array would turn into what size.
I suggest that you move your data into external resources in .jar file, it will also compress much better. also try optimizing it
String[] strs = new String[] { "1", "2", ... , "6" };
for (String s : strs) {
System.out.println(s);
}
This is a question about java internals.
In the above code sample, how does the foreach loop figure out how long the array is? Are arrays actually objects internally or is it using stuff like sizeof that is inaccessible to front end programmers?
I have a feeling I'm just missing something stupid, but I figure it could also be cool. :-)
I compiled the following code:
public class ArrayIterator
{
public static void main(String[] argv)
{
String[] strs = new String[] { "1", "2", "3", "4", "5" };
enhancedPrint(strs);
normalPrint(strs);
}
public static void enhancedPrint( String[] strs )
{
for (String s : strs)
{
System.out.println(s);
}
}
public static void normalPrint( String[] strs )
{
String[] localArray = strs;
int len = localArray.length;
for (int i = 0; i < len; i++)
{
String s = localArray[i];
System.out.println(s);
}
}
}
This is the disassembled (javap -c ArrayIterator) bytecode for the iterating functions:
The enhanced print:
public static void enhancedPrint(java.lang.String[]);
Code:
0: aload_0
1: astore_1
2: aload_1
3: arraylength
4: istore_2
5: iconst_0
6: istore_3
7: iload_3
8: iload_2
9: if_icmpge 31
12: aload_1
13: iload_3
14: aaload
15: astore 4
17: getstatic #10; //Field java/lang/System.out:Ljava/io/PrintStream;
20: aload 4
22: invokevirtual #11; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
25: iinc 3, 1
28: goto 7
31: return
A normal for loop:
public static void normalPrint(java.lang.String[]);
Code:
0: aload_0
1: astore_1
2: aload_1
3: arraylength
4: istore_2
5: iconst_0
6: istore_3
7: iload_3
8: iload_2
9: if_icmpge 31
12: aload_1
13: iload_3
14: aaload
15: astore 4
17: getstatic #10; //Field java/lang/System.out:Ljava/io/PrintStream;
20: aload 4
22: invokevirtual #11; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
25: iinc 3, 1
28: goto 7
31: return
As you can see, in both cases, the compiler is loading the arrays length (strs.length) and looping against it. We see that the enhanced for-each loop, in the case of an Array is syntactic sugar for looping against the array's length (rather than in an Object's case where it uses an Iterator).
I have edited the 'normal' for loop such that it is much less idiomatic, but that it has the same bytecode as the enhanced for loop. For all intents and purposes, the normal for loop version is what the compiler generates when it compiles the enhanced for each loop.
Yes, there is something akin to the C++ sizeof operator -- it's the length instance variable (which gives the number of elements in the array, not the size in bytes.) The length field is always a public member of the array, so it is accessible to Java programmers.
And yes, arrays are objects, and not just internally.
(More broadly, the for loop syntax works as described in the question that org.life.java linked to; but that isn't quite what you were asking.)
Yes, arrays are objects with a "length" field. Java Language Specification: http://java.sun.com/docs/books/jls/third_edition/html/arrays.html#64347