What code does the compiler generate for autoboxing? - java

When the Java compiler autoboxes a primitive to the wrapper class, what code does it generate behind the scenes? I imagine it calls:
The valueOf() method on the wrapper
The wrapper's constructor
Some other magic?

You can use the javap tool to see for yourself. Compile the following code:
public class AutoboxingTest
{
public static void main(String []args)
{
Integer a = 3;
int b = a;
}
}
To compile and disassemble:
javac AutoboxingTest.java
javap -c AutoboxingTest
The output is:
Compiled from "AutoboxingTest.java"
public class AutoboxingTest extends java.lang.Object{
public AutoboxingTest();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_3
1: invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
4: astore_1
5: aload_1
6: invokevirtual #3; //Method java/lang/Integer.intValue:()I
9: istore_2
10: return
}
Thus, as you can see, autoboxing invokes the static method Integer.valueOf(), and autounboxing invokes intValue() on the given Integer object. There's nothing else, really - it's just syntactic sugar.

I came up with a unit test that proves that Integer.valueOf() is called instead of the wrapper's constructor.
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import org.junit.Test;
public class Boxing {
#Test
public void boxing() {
assertSame(5, 5);
assertNotSame(1000, 1000);
}
}

If you look up the API doc for Integer#valueOf(int), you'll see it was added in JDK 1.5. All the wrapper types (that didn't already have them) had similar methods added to support autoboxing. For certain types there is an additional requirement, as described in the JLS:
If the value p being boxed is true, false, a byte, a char in the range \u0000 to \u007f, or an int or short number between -128 and 127, then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2. §5.1.7
It's interesting to note that longs aren't subject to the same requirement, although Long values in the -128..127 range are cached in Sun's implementation, just like the other integral types.
I also just discovered that in my copy of The Java Programming Language, it says char values from \u0000 to \u00ff are cached, but of course the upper limit per the spec is \u007f (and the Sun JDK conforms to the spec in this case).

I'd recommend getting something like jad and decompiling code a lot. You can learn quite a bit about what java's actually doing.

Related

Java compiler allows accessing uninitialized blank final field using 'this' keyword? Is this a bug? [duplicate]

This question already has answers here:
Use of uninitialized final field - with/without 'this.' qualifier
(4 answers)
Closed 8 years ago.
I wrote this piece of code and it seems compiler allows accessing uninitialized blank final field when accessed using 'this' keyword:
public class TestClass
{
public final int value1;
public int value2;
TestClass(int value) {
value2 = 2 + this.value1; // access final field using 'this' before initialization gives no compiler error
//value2 = 2 + value1; // uncomment it gives compile time error - variable value1 might not have been initialized
value1 = value;
}
public static void main(String args[]) {
TestClass tc = new TestClass(10);
System.out.println("\nTestClass Values : value1 =  " + tc.value1 + " , value2 =  " + tc.value2);
}
}
I tried compiling it on 1.5, 1.6, & 1.7 and got same result in all three of them.
To me it looks like compiler bug because compiler must throw error in this case but with 'this' keyword it doesn't and thus creates scope of coding error as it will go unnoticed by the programmer since no compile-time or run-time error will be thrown.
FEW POINTS WHY IT IS NOT A DUPLICATE
- all answers are explaining how it works and what JLS says, fine, but my real intent here is should that be allowed at the first place?
- my question here is more from programmer's point of view and not language semantics
This is not a bug. This a feature for Java Specification 1.6 and lower.
The final field can be accessed at any part of the code. There is no restriction about it.
The only restriction in case of final is that it has to be initialized before class instance is created.
When you use this, you express that it is element of the object that is being constructed.
Since the specification 1.7 because of change we may say that this is bug in some implementation of compilers.
But since 1.8 the code will produce same error for this.value1 or value1.
In Java ints have a default value of 0, so even if you did not initialize it, the compiler has still assigned 0 as value.
Fields that are declared but not initialized will be set to a reasonable default by the compiler. Generally speaking, this default will be zero or null, depending on the data type.
Source: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
Note that this does not apply to local variables, only field variables have a default value.
I used the following code
public class HelloWorld {
public final int value1;
public int value2;
public HelloWorld(int value){
System.out.println(this.value1);
System.out.println(this.value2);
value1 = value;
}
public static void main(String args[]) {
}
}
and the bytecode it generates is
Compiled from "HelloWorld.java"
public class test.HelloWorld extends java.lang.Object{
public final int value1;
public int value2;
public test.HelloWorld(int);
Code:
0: aload_0
1: invokespecial #11; //Method java/lang/Object."<init>":()V
4: getstatic #14; //Field java/lang/System.out:Ljava/io/PrintStream;
7: aload_0
8: getfield #20; //Field value1:I
11: invokevirtual #22; //Method java/io/PrintStream.println:(I)V
14: aload_0
15: iload_1
16: putfield #20; //Field value1:I
19: return
public static void main(java.lang.String[]);
Code:
0: return
}
If you notice JVM does a getstatic call in case of final and getfield in case of normal instance variable. Also now if you look at the specs for getstatic it says
On successful resolution of the field, the class or interface that declared the resolved field is initialized (§5.5) if that class or interface has not already been initialized.
So if you use this with a final variable then it is initialize it. Not it will initialize this.value1 and not value1 which is final. You still have to initialize it before using.

implementing a generic method with varargs

In my code, it appears convenient to use varargs when implementing a generic method when the type is an array:
public interface Codec<D,E> {
E encode(D decoded);
D decode(E encoded);
}
public class MyCodec implements Codec<byte[], char[]> {
#Override char[] encode(byte... decoded) {...}
#Override byte[] decode(char... encoded) {...}
}
When I write this, Eclipse shows a warning:
Varargs methods should only override or be overridden by other varargs
methods unlike MyCodec.encode(byte...) and
Codec.encode(byte[])
Should I just ignore the warning, or is this going to cause some unforeseen problems?
This is an Eclipse-specific warning. It has nothing to do with generics specifically and can be reproduced with this example:
class A {
m(int[] ints) { }
}
class B extends A {
#Override
m(int... ints) { }
}
As the other answers point out, varargs are purely a compile-time feature and there's no difference at runtime. I tried searching for the specific reasoning behind the warning but couldn't turn anything up. Likely it's considered bad practice to alternate method overrides between varargs and non-varargs because it's confusing and arbitrary. But this is in general - your use case seems more reasonable as long as callers are always going to be using a statically-typed MyCodec instead of coding to interface with a Codec<byte[], char[]>.
Unfortunately there is no way to suppress this warning - even #SuppressWarnings("all") won't make it yield. Which is unfortunate considering how obscure of a warning it is. Here's an ancient conversation about this same issue: http://echelog.com/logs/browse/eclipse/1196982000 (scroll to 20:45:02) - proving it's bit people long before you. Seems like an Eclipse bug that it can't be suppressed.
I wrote two test files. Here's the first:
public class Test {
public static void main(String... args) {
System.out.println(java.util.Arrays.toString(args));
}
}
And here's the second:
public class Test {
public static void main(String[] args) {
System.out.println(java.util.Arrays.toString(args));
}
}
(The only difference between these two files is the String[] args vs String... args.)
Then, I ran javap -c on each file to see the disassembly. The contents of the main method were identical:
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: aload_0
4: invokestatic #3 // Method java/util/Arrays.toString:([Ljava/lang/Object;)Ljava/lang/String;
7: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
10: return
The only difference was the method header, which was simply the method signature of each method:
public static void main(java.lang.String[]);
public static void main(java.lang.String...);
With this in mind, I would say that it's a safe assumption that nothing bad will happen.
According to the bytecode, no problem.
public byte[] encode(char...);
flags: ACC_PUBLIC, ACC_VARARGS
LineNumberTable:
line 4: 0
LocalVariableTable:
Start Length Slot Name Signature
0 2 0 this LMyEncoder;
0 2 1 args [C // char[]
Code:
stack=1, locals=2, args_size=2
0: aconst_null
1: areturn // return null;
LineNumberTable:
line 4: 0
LocalVariableTable:
Start Length Slot Name Signature
0 2 0 this LMyEncoder;
0 2 1 args [C
public java.lang.Object encode(java.lang.Object);
flags: ACC_PUBLIC, ACC_BRIDGE, ACC_VARARGS, ACC_SYNTHETIC
LineNumberTable:
line 1: 0
LocalVariableTable:
Start Length Slot Name Signature
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: checkcast #27 // class "[C" -> char[]
5: invokevirtual #28 // Method encode:([C)[B -> return byte[]
8: areturn
LineNumberTable:
line 1: 0
LocalVariableTable:
Start Length Slot Name Signature
If you make a call using one reference of the interface, the method with the flag ACC_BRIDGE check (checkcast) if the type of the argument is the same as is defined in the type parameter (java.lang.ClassCastException otherwise, but will never happen if you allways provides the type parameter), then run the method implementation.
In another hand, if you compile this with javac, none warning is show.

Use Scala constants in Java

I am currently evaluating Scala for future projects and came across something strange. I created the following constant for us in a JSP:
val FORMATED_TIME = "formatedTime";
And it did not work. After some experimenting I decided to decompile to get to the bottom of it:
private final java.lang.String FORMATED_TIME;
public java.lang.String FORMATED_TIME();
Code:
0: aload_0
1: getfield #25; //Field FORMATED_TIME:Ljava/lang/String;
4: areturn
Now that is interesting! Personally I have been wondering for quite a while why an inspector needs the prefix get and a mutator the prefix set in Java as they live in different name-spaces.
However it might still be awkward to explain that to the rest of the team. So is it possible to have a public constant without the inspector?
This is because of the Uniform Access Principle, i.e.: Methods and Fields Are Indistinguishable
See this answer
In Scala 2.8.0 this means if you have
a companion object, you lose your
static forwarders)
If you have this in Scala:
//Scala
object CommonControler {
val FORMATED_TIME = "formatedTime";
}
You may use it like this from Java
//Java
// Variables become methods
CommonControler$.MODULE$.FORMATED_TIME();
// A static forwarder is avaliable
CommonControler.FORMATED_TIME();
Also see the book Scala in Depth
Also note the #scala.reflect.BeanProperty for classes.
I had a further look into the decompiled code and noted something else. The variables are not actually static. So my next idea was to use an object instead:
object KommenControler
{
val FORMATED_TIME = "formatedTime";
} // KommenControler
But now things turn really ugly:
public final class ….KommenControler$ extends java.lang.Object implements scala.ScalaObject{
public static final ….KommenControler$ MODULE$;
private final java.lang.String FORMATED_TIME;
public static {};
Code:
0: new #9; //class …/KommenControler$
3: invokespecial #12; //Method "<init>":()V
6: return
public java.lang.String FORMATED_TIME();
Code:
0: aload_0
1: getfield #26; //Field FORMATED_TIME:Ljava/lang/String;
4: areturn
So I get an additional class ending on $ which has a singleton instance called MOUDLE$. And there is still the inspector. So the access to the variable inside a jsp becomes:
final String formatedTime = (String) request.getAttribute (….KommenControler$.MODULE$.FORMATED_TIME ());
This works as expected and I personally can live with it but how am I going to explain that to the team?
Of course if there is a simpler way I like to hear of it.

Java: new Something().method() vs a temp variable

maybe it's dumb but is there a difference between
new Something().method();
and
Something tmpSomething = new Something();
tmpSomething.method();
as I was calling only one method on this particular object, I chose the first solution but I'm not sure that this is exactly the same behavior...
I just want to mention the constructor initializes a Writer and method writes in this file...
I did a quick test. This is the extremely trivial test code:
public class TestLiveness
{
public static void test1()
{
System.out.println(new Square(4).square());
count();
}
public static void test2()
{
Square t = new Square(4);
System.out.println(t.square());
count();
}
private static void count()
{
for(int i=0; i<1000000; i++)
System.out.println(i);
}
static class Square
{
private int val;
Square(int val)
{
this.val = val;
}
int square()
{
return val * val;
}
}
}
Javap shows that the two methods are compiled differently; chaining doesn't touch the local variable table whereas the temporary variable does indeed stick around until the method returns. However, the VM/JIT compiler may still perform liveness analysis and allow the instance to be garbage collected before the method returns.
public static void test1();
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: new #3; //class TestLiveness$Square
6: dup
7: iconst_4
8: invokespecial #4; //Method TestLiveness$Square."<init>":(I)V
11: invokevirtual #5; //Method TestLiveness$Square.square:()I
14: invokevirtual #6; //Method java/io/PrintStream.println:(I)V
17: invokestatic #7; //Method count:()V
20: return
public static void test2();
Code:
0: new #3; //class TestLiveness$Square
3: dup
4: iconst_4
5: invokespecial #4; //Method TestLiveness$Square."<init>":(I)V
8: astore_0
9: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
12: aload_0
13: invokevirtual #5; //Method TestLiveness$Square.square:()I
16: invokevirtual #6; //Method java/io/PrintStream.println:(I)V
19: invokestatic #7; //Method count:()V
22: return
There is no difference whatsoever except that in the second case you have an unnecessary variable lying around that makes the code harder to maintain.
Also, objects that get created only to be discarded after calling a single method constitute a code smell.
They are the same. Although constructing an object and only calling a single method on it may indicate poor design. Why not allow Something.method(); without needing to expose a constructor?
Well, in the second case you've got the object tmpSomething so you can use it throughout in the code but in the first example you don't. So you can't.
I imagine the first method is probably a touch more efficient but probably not the best practice for Java conventions.
If you can get some value from the first call maybe you might want to define your method static:
public static ____ method() {
}
There is a subtle difference between the two snippets, but only when viewed within their scope. Consider them within methods:
public void doSomething1() {
new Something().method();
doSomeLongRunningSomething();
}
public void doSomething2() {
Something tmpSomething = new Something();
tmpSomething.method();
doSomeLongRunningSomething();
}
In the first method, the 'something' is immediately available for garbage collection while in the second method, tmpSomething stays within scope during the run of doSomeLongRunningSomething. If you are doing anything interesting during the finalize (e.g. closing the file), this could introduce some quirks.
That said, my preference is for the second example and naming the new instance as it assists the debugging processing. While stepping through code you have a named instance that is easier to watch. That doesn't apply when you're getting pre-existing instances in which case I find chaining methods more readable, e.g. myDog.getEyes().getLeftEye().getColorAsRgb().getRed().
Firstly I'll agree with everyone else and say they are the same in terms of function.
However, I'm of the opposite opinion on what most are saying in this post, which is that I think the first example is the way to go.
And with the first example, I'd extend it even further with some form of dependency injection. This will get you in the habit of giving you the ability to test things if you need to inject a mock/test version of that 'Something' class.
Also by not train wrecking (doing more than one operation on the one line which is a code smell, e.g. new dog().getEyes().getColour();), in my opinion improves readability as well as optimises your ability to refactor later on. Just because at the moment you only call that one method on that object doesn't mean you won't need that object to do something else on it later meaning you will have to extract a variable for that 'Something' object anyway.
Nothing wrong with that, even when you call only one function.
Have a look at Fluent Interfaces on Wikipedia or Fluent Interfaces by Martin Fowler

Is this really widening vs autoboxing?

I saw this in an answer to another question, in reference to shortcomings of the Java spec:
There are more shortcomings and this is a subtle topic. Check this out:
public class methodOverloading{
public static void hello(Integer x){
System.out.println("Integer");
}
public static void hello(long x){
System.out.println("long");
}
public static void main(String[] args){
int i = 5;
hello(i);
}
}
Here "long" would be printed (haven't checked it myself), because the compiler chooses widening over auto-boxing. Be careful when using auto-boxing or don't use it at all!
Are we sure that this is actually an example of widening instead of autoboxing, or is it something else entirely?
On my initial scanning, I would agree with the statement that the output would be "long" on the basis of i being declared as a primitive and not an object. However, if you changed
hello(long x)
to
hello(Long x)
the output would print "Integer"
What's really going on here? I know nothing about the compilers/bytecode interpreters for java...
In the first case, you have a widening conversion happening. This can be see when runinng the "javap" utility program (included w/ the JDK), on the compiled class:
public static void main(java.lang.String[]);
Code:
0: iconst_ 5
1: istore_ 1
2: iload_ 1
3: i2l
4: invokestatic #6; //Method hello:(J)V
7: return
}
Clearly, you see the I2L, which is the mnemonic for the widening Integer-To-Long bytecode instruction. See reference here.
And in the other case, replacing the "long x" with the object "Long x" signature, you'll have this code in the main method:
public static void main(java.lang.String[]);
Code:
0: iconst_ 5
1: istore_ 1
2: iload_ 1
3: invokestatic #6; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
6: invokestatic #7; //Method hello:(Ljava/lang/Integer;)V
9: return
}
So you see the compiler has created the instruction Integer.valueOf(int), to box the primitive inside the wrapper.
Yes it is, try it out in a test. You will see "long" printed. It is widening because Java will choose to widen the int into a long before it chooses to autobox it to an Integer, so the hello(long) method is chosen to be called.
Edit: the original post being referenced.
Further Edit: The reason the second option would print Integer is because there is no "widening" into a larger primitive as an option, so it MUST box it up, thus Integer is the only option. Furthermore, java will only autobox to the original type, so it would give a compiler error if you leave the hello(Long) and removed hello(Integer).
Another interesting thing with this example is the method overloading. The combination of type widening and method overloading only working because the compiler has to make a decision of which method to choose. Consider the following example:
public static void hello(Collection x){
System.out.println("Collection");
}
public static void hello(List x){
System.out.println("List");
}
public static void main(String[] args){
Collection col = new ArrayList();
hello(col);
}
It doesn't use the run-time type which is List, it uses the compile-time type which is Collection and thus prints "Collection".
I encourage your to read Effective Java, which opened my eyes to some corner cases of the JLS.

Categories