Does having a wrapper object return value (e.g. Integer) cause auto boxing in Java?
Asked Answered
U

3

9

I couldn't find a definitive answer for this seemingly simple question. If I write a method like this:

public Integer getAnInt() {
  int[] i = {4};
  return i[0];
}

is the return value autoboxed into an Integer, or does it depend on what happens to the value after it's returned (e.g. whether the variable it is assigned to is declared as an Integer or int)?

Unthinkable answered 12/8, 2022 at 15:1 Comment(4)
There's no good reason for your public API to return a concrete Integer anyway. You should return an int and let autoboxing promote it to an Integer if needed.Gingergingerbread
@SilvioMayolo That wasn't the question. I didn't write the api I'm working withUnthinkable
@SilvioMayolo That there is "no good reason" is simply not correct. For example, there are times when you are forced to return Integer, say if you implement a generic interface Container<Integer>, where Container<T> has a T-bearing get method, then get would have to return Integer. (Maybe yoy meant "In general, you should prefer returning int", which would have been true.)Holocaust
How does this question relate to Python?Apocrine
C
8

Yes, boxed

It will be (auto)boxed in the bytecode (.class file) because it's part of the public API, so other code might depend on the return value being an Integer.

The boxing and unboxing might be removed at runtime by the JITter under the right circumstances, but I don't know if it does that sort of thing.

Cellule answered 12/8, 2022 at 15:4 Comment(0)
H
22

You are asking two different questions, and its important to separate them. The first is a language-level question: how does the language mediate the difference between int and Integer in a context such as return. The second is (by implication) a cost-model question -- will returning Integer cause useless heap allocation. Many developers conflate the two.

To the first question, you have a method that returns Integer but the operand of return is an expression of type int. A return is treated, essentially, as an assignment; you are trying to assign int to Integer. JLS 5.2 says that a boxing conversion is permitted in an assignment context. So yes, that int will be the subject of a boxing conversion.

But the fact that you are asking the question at all suggests that somehow you are scared of the performance overhead of boxing, hence the second, implied part of your question. Here is where it gets (a) murky, and (b) probably irrelevant. At runtime, whether heap allocation actually occurs depends on (a) whether the int is large (boxing caches the boxes for small integers) and (b) whether the method is inlined. If the method is inlined, the JIT will see that you are going int -> Integer -> int and elide the conversions.

And, even if boxing happens, does it really matter? How many billion-billion boxing operations would it take for this to show up on your performance metrics? Even if you pay the full cost of boxing, allocation and garbage collection of short-lived temporary objects is very cheap.

Holocaust answered 12/8, 2022 at 15:18 Comment(0)
C
8

Yes, boxed

It will be (auto)boxed in the bytecode (.class file) because it's part of the public API, so other code might depend on the return value being an Integer.

The boxing and unboxing might be removed at runtime by the JITter under the right circumstances, but I don't know if it does that sort of thing.

Cellule answered 12/8, 2022 at 15:4 Comment(0)
T
3

Adding to what has been said, whenever you are confused about what the compiler does under the hood to your code, what I usually do and recommend, is to write a minimal example, compile it, then use a decompiler to check how the compiler manipulated the class files. You could then see the compiler actually translates your code to:

   public Integer getAnInt() {
      int[] var1 = new int[]{4};
      return Integer.valueOf(var1[0]);
   }

Technically, you asked the compiler to use autoboxing when you put Integer as the return type. It should not matter what happens to the value after it is returned, but for optimization reasons, a JIT compiler can avoid this behavior, as was already stated.

Here's my flow to decompile:

  1. Compile your java file with javac. I do this in the command line.
  2. Either download a decompiler in your system or find one online. I use javadecompilers which is very easy to use and has the advantage of having multiple decompilers available to try.
  3. Add your resulting class file to it and wait to generate the source code. You may choose to try a different decompiler as each can differ a bit in the output generated. I used FernFlower to decompile your example.

Note: A disadvantage to the online version is that if your code has multiple classes,javac will generate separate class file for each. You can choose either to add only the class file that you are interested to the decompiler (a minimal example should not have more than a few classes anyway and most of the time you'll be interested in decompiling the bytecode of a certain class) - or - you can either choose to create a jar with all of class files and search for a decompiler capable of decompiling entire jar files. I prefer adding the class files directly.

Lastly, don't forget the Java Disassembler javap always available in the Java SDK. Using -c prints out the disassembled code - the instructions that comprises the Java bytecode - for each of the methods in the class. These are documented in the JVM Specification. You can understand some on the spot because method invocations to the Java standard library are marked in comments:

public static java.lang.Integer getAnInt();
    Code:
       0: iconst_1
       1: newarray       int
       3: dup
       4: iconst_0
       5: iconst_4
       6: iastore
       7: astore_0
       8: aload_0
       9: iconst_0
      10: iaload
      11: invokestatic  #7  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      14: areturn

A nice way to check that Integer.valueOf gets called in your code.

Tabanid answered 12/8, 2022 at 16:37 Comment(4)
This may tell you about the bytecode, but it won't tell you about what the JIT can do.Tamper
No, but still it's a very instructive way to get a general understanding what the compiler is doing behind.Tabanid
Good idea! But this answer would be even better if you show how to decompile the byte code.Baklava
Improved answer! Thank you for your kind feedback.Tabanid

© 2022 - 2024 — McMap. All rights reserved.