When we do some operation on a variable, we just change pointer to another literal? I am a bit confused understanding the exact meaning of the term 'literal'.
Suppose we have int x = 3; // 3 is literal and immutable , x is variable
Doing operation for ex: x++
And now x == 4; so our var x is just pointing to a new literal. Does the computer just remember that 3 + 1 is 4?
x isn't a pointer.
The JVM spec just says what happens; how it happens is intentionally not specified. So, this answer merely explains how it works on all JVMs I'm aware of. Almost as good. It should certainly clarify matters:
class Example {
int x = 3;
void foo() {
x++;
}
}
Here, any time new Example()
is executed, some block of memory is reserved for this instance. An instance of an object is simply a block of memory that holds its basic properties (including that this is an object of type Example
) and room to store the value of every non-static field. In this case, int x
- that's a non-static field.
Primitives are special data types: It's a hard coded list: int, long, short, byte, double, float, boolean, and char. That's it. That's the whole list, you can't add any new types. They are 'special' - any value of a primitive type is just the value. not a pointer.
Thus, int x = 3
means that any attempt to make a new Example instance (new Example()
) will, as mentioned, reserve some space in memory to store the value of the x
field, and that value is directly 3. It's not 'a pointer to a 3 object'. It's just.. 3. It'll take at least 32-bits (as int
is 32 bits), it might effectively take 64 (CPUs pretty much require that objects are nicely aligned: That they start on a value that is divisible by 64, on 64-bit CPUs).
x++
simply finds that memory position with the bit sequence 0000....0000011 (0011
is binary for '3'), and increments it, turning that into 0000....0000100.
In contrast, let's try with an object - anything that isn't on that list of primitives is an object, and all such values are pointers. (In java speak, 'references'). So, in this very slightly changed code:
class Example {
Integer x = 3;
void foo() {
x++;
}
}
Something very very different is going on. For starters, auto-boxing: That is syntax sugar and is compiled as if you wrote:
class Example {
Integer x = Integer.valueOf(3);
void foo() {
x = Integer.valueOf(x.intValue() + 1);
}
}
Why? Because the JLS says so - that's what happens when you try to x++
where x
is a non-primitive type, but, is autoboxable to an int
.
So, what happens here? Who knows? Who cares - the code of valueOf
does what it does. It acts as the spec says it acts, it's generally not useful to ask how. But, if you're interested:
Integer
(the class), upon loading (which it always will, as its such a core class) creates a 'cache', and makes 1 Integer object for each value between -128 and +127. Integer.valueOf
will return you the value from the cache if possible (i.e. the argument you pass to it is between -128 and +127) otherwise it creates a new Integer object. Given that 3 and 4 fit, you get something like this:
package java.lang;
public class Integer {
private static final Integer[] cache = new Integer[255];
static {
for (int i = 0; i < 256; i++) {
cache[i] = new Integer(i - 128);
}
}
public static Integer valueOf(int v) {
if (v >= -128 && v <= 127) return cache[v + 128];
return new Integer(v);
}
private final int value;
public Integer(int v) {
this.value = v;
}
public int intValue() {
return v;
}
}
x + 1
in java works because the spec says so. It doesn't have some lookup table that says '3 + 1 is 4', the concept of adding is baked into CPUs. Forget about pointers and such, computers are binary so numbers can only exist strictly in terms of zeroes and ones. Hence, even -1 is tricky (there's no '-'. Just zeroes and ones!). However, just because a number is stored in binary doesn't mean that adding is somehow impossible.
Given, say, 5 and 9:
to add them, you do the same thing you'd do when adding 2 decimal numbers. Add each element and make sure to carry any excess. So:
???????0
??????10
.?????110
.... and so on. Arriving at 00001110
. There is no need for lookup tables to do this. Just a repeated application of this trivial table:
carry-in | digit1 | digit2 | output | carry |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 0 |
0 | 0 | 1 | 1 | 0 |
0 | 1 | 1 | 0 | 1 |
1 | 0 | 0 | 1 | 0 |
1 | 1 | 0 | 0 | 1 |
1 | 0 | 1 | 0 | 1 |
1 | 1 | 1 | 1 | 1 |
That logic (that 'table' + the logic to repeatedly apply it to every digit) is baked into the silicon of your CPU.