Reputation: 65
I have a silly question for you all. Given the following Java Code
public void funct(String a) {
byte[] bytearr;
bytearr = new byte[a.getBytes().length];
bytearr = a.getBytes();
}
Does the new call change anything? In particular, is the code processed in a different way from
public void funct(String a) {
byte[] bytearr;
bytearr = a.getBytes();
}
I am asking because, when executed, both present the same results and I can't get if
More in general, any suggestion to observe memory allocations/magic behaviour behind JVM would be very appreciated.
Thanks!
Upvotes: 1
Views: 295
Reputation: 26056
They are different, let us take a look at the bytecode:
1. version:
L0
LINENUMBER 9 L0
ALOAD 0
ICONST_0
AALOAD
INVOKEVIRTUAL java/lang/String.getBytes ()[B
ARRAYLENGTH
NEWARRAY T_BYTE
ASTORE 1
L1
LINENUMBER 10 L1
ALOAD 0
ICONST_0
AALOAD
INVOKEVIRTUAL java/lang/String.getBytes ()[B
ASTORE 1
L2
LINENUMBER 11 L2
RETURN
L3
LOCALVARIABLE args [Ljava/lang/String; L0 L3 0
LOCALVARIABLE bytearr [B L1 L3 1
MAXSTACK = 2
MAXLOCALS = 2
2. version:
L0
LINENUMBER 9 L0
ALOAD 0
ICONST_0
AALOAD
INVOKEVIRTUAL java/lang/String.getBytes ()[B
ASTORE 1
L1
LINENUMBER 10 L1
RETURN
L2
LOCALVARIABLE args [Ljava/lang/String; L0 L2 0
LOCALVARIABLE bytearr [B L1 L2 1
MAXSTACK = 2
MAXLOCALS = 2
The difference is in those instructions comming from the extra line:
LINENUMBER 9 L0
ALOAD 0
ICONST_0
AALOAD
INVOKEVIRTUAL java/lang/String.getBytes ()[B
ARRAYLENGTH
NEWARRAY T_BYTE
ASTORE 1
This introduces additional overhead (getBytes
being called twice, more instructions). By invoking bytearr = a.getBytes()
jvm already handles the size of the array being stored.
But since the first initialization is redundant, it will probably be optimized by the compiler at some point (after enough runs). Still, there is no need for additional instructions and less readable code.
Upvotes: 1
Reputation: 2756
The end result of both blocks of code is the same. The first version does some uneccessary extra work.
Version 1
Lets go through the first version step by step.
Step 1)
bytearr = new byte[a.getBytes().length];
A new empty array is created and bytearr
points to it.
Step 2)
bytearr = a.getBytes();
a.getBytes()
creates a second array. bytearr
is updated to point to that new array. The old (blue) array is now garbage because no reference to it is held anymore. The garbage collector of the JVM will free the memory occupied by it eventually.
Version 2
bytearr = a.getBytes();
bytearr
is directly pointing to the array created by a.getBytes()
. The end result is the same, but this version is more efficient.
More details about version 1
Actually version 1 creates even one more array during the call a.getBytes().length
. The initial explaination skipped over it to keep it simple.
So actually there are 3 array instances involved in version 1:
a.getBytes().length
to measure the size (not shown in the diagrams for simplicty).new byte[...]
with that size (the blue one).a.getBytes()
(the green one).Upvotes: 2
Reputation: 49
The only difference is that you're creating an extra, unnecessary object in the first snippet. If you want to prove it, you could point a second array reference at the first, print out their equivalence, then call the string.getBytes() on the first array and test their equivalence again:
String aString = new String("something");
byte[] byteArray1 = new byte[aString.length()];
byte[] byteArray2 = byteArray1;
System.out.println(byteArray1==byteArray2);
byteArray1 = aString.getBytes();
System.out.println(byteArray1==byteArray2);
It prints out true before the aString.getBytes() because the references are pointing at the same object. Then aString.getBytes() returns a new byte[] array, so byteArray1 no longer == byteArray2. Does this answer the question or were you looking for something else?
Upvotes: 2