values can be stored in an object only if you have called a field in the class or method.
This statement doesn't make any sense. I can't tell if it is wrong or right, it just... doesn't make sense.
it shouldn't be able to call its value field without instantiating an object since value isn't static. I just can't wrap my head around how this is even possible.
Javac sees that and goes: Hey, you're shoving a square peg (a constant of type int
) into a round hole (an object typed variable) - this doesn't make sense. Except, explicitly called out in the Java Language Specification, if an int
expression shows up in a place where int
expressions should not be, but an Integer
expression works fine, then 'apply autoboxing'.
'apply autoboxing' means: Assume the programmer meant to write: Integer.valueOf(the expression)
instead of what they wrote.
Thus:
Integer x = 56;
Integer x = Integer.valueOf(56);
are identical. They are so identical, they produce the same bytecode. That call to valueOf is in your class file, no matter how you write it. Let's test:
> cat Test.java
class Test {
Integer x = 56;
}
> javac Test.java
(`javap` is part of java distributions and prints bytecode)
> javap -private -c Test
Compiled from "Test.java"
class Test {
java.lang.Integer x;
Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: bipush 56
7: invokestatic #7 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
10: putfield #13 // Field x:Ljava/lang/Integer;
13: return
}
Look at that - calls to the static method Integer.valueOf
, even though Integer.valueOf
appears exactly nowhere in our Test.java file.
So, how does Integer.valueOf work?
Essentially, it works like this:
package java.lang;
public class Integer {
private static final Integer[] CACHE = generateCache();
private final int value;
public Integer(int value) {
this.value = value;
}
private static Integer[] generateCache() {
for (int i = 0; i < 256; i++) {
CACHE[i - 128] = new Integer(i);
}
}
public static Integer valueOf(int v) {
if (v >= -128 && v < 128) return CACHE[i + 128];
return new Integer(v);
}
}
In other words, the Integer class pre-creates 256 integer objects, from -128 to +127 (why those values? Eh, cuz sun thought those would come up so often, it'd be worthwhile to cache them, 25 years ago). If you valueOf()
with a value between -128 and +127 you get one of the caches. If you valueOf outside of it, you get a new object.
We can prove that too:
> cat Example.java
class Example {
public static void main(String[] args) {
Integer a = -100;
Integer b = -100;
Integer c = 200;
Integer d = 200;
System.out.println("a == b? " + (a == b));
System.out.println("c == d? " + (c == d));
System.out.println("ident-hash a: " + System.identityHashCode(a));
System.out.println("ident-hash b: " + System.identityHashCode(b));
System.out.println("ident-hash c: " + System.identityHashCode(c));
System.out.println("ident-hash d: " + System.identityHashCode(d));
}
}
> java Example.java
a == b? true
c == d? false
ident-hash a: 1880794513
ident-hash b: 1880794513
ident-hash c: 1991313236
ident-hash d: 736778932
This code shows that for -100, that Integer.valueOf call is returning the exact same object (==
compares reference identity, i.e.: Is it the same object, when used on objects, it does not compare values. a and b are just pointing to the same object, whereas c and d are pointing at different objects that have the same values).
It's like a bunch of identical houses build in the suburbs someplace: a and b are like pieces of paper with the same address written on them, whereas c and d are like pieces of paper with a different address on each, but the two houses at these addresses look the same.