6

I always understood static variables to share one instance whenever they were referenced. I wanted to put this to the test but the results were different than I had expected.

static Integer counter = 0;
static Integer test = counter;

public static void main(String args[]) {
     counter++;
     System.out.println("counter: " + counter);
     System.out.println("test: " + test);
}

output:

counter: 1

test: 0

Since test references counter I thought that when I increment counter then test will automatically be incremented as well. However, it seems test is referencing 0 from somewhere, question is, where?

Community
  • 1
  • 1
  • They are both primitives not objects. `test` is originally `0`, if you want to increment test, you need to call `test++`. – Jared Burrows Apr 04 '15 at 23:18

5 Answers5

3

Since test references counter

This assumption is false. In Java, you cannot reference variables. What is stored in a variable is a value. That value can either be a primitive type value or a reference type value. In the case of primitives, the value is the value of the primitive. In the case of reference types,

The reference values (often just references) are pointers to these objects, and a special null reference, which refers to no object.

In

int a = 0;
int b = a;

the variable a is evaluated to produce a value, 0, and that value is stored in b.

In

Integer a = 0;
Integer b = a;

0 is converted to an Integer through Integer.valueOf(int) and the value, a reference to an Integer object is stored in a. Then a is evaluated, producing the value of that reference to an Integer object, and that value is stored in b.

This is the same concept discussed in

Also, the fact that the variables are static is irrelevant.

The only way around this is to update test manually i.e.

counter++; 
test = counter;
Community
  • 1
  • 1
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • Is there a JLS reference that talks about the assignment conversion of boxed types to other boxed types explicitly? I looked around and could not find it. – merlin2011 Apr 04 '15 at 23:31
  • 1
    @merlin2011 Do you mean [boxing conversion](http://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.7)? – Sotirios Delimanolis Apr 04 '15 at 23:32
  • That only talks about `int` to `Integer` and the section after talks about `Integer` to `int`. Here we are looking at `Integer` to `Integer` direct assignment, which is what I couldn't find a reference about. – merlin2011 Apr 04 '15 at 23:33
  • 1
    @merlin2011 Yes, [here](http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.26.1), last point. _the value of the right-hand operand is converted to the type of the left-hand variable, is subjected to value set conversion (§5.1.13) to the appropriate standard value set (not an extended-exponent value set), and the result of the conversion is stored into the variable._ – Sotirios Delimanolis Apr 04 '15 at 23:34
  • I looked at 5.1.13 and did not find anything about boxing or unboxing. I'm probably misunderstanding it. – merlin2011 Apr 04 '15 at 23:37
  • 1
    @merlin2011 No, 5.1.13 is just an additional evaluation. The conversion occurs during _the value of the right-hand operand is converted to the type of the left-hand variable_, which is discussed in [5.2](http://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.2). – Sotirios Delimanolis Apr 04 '15 at 23:40
3

Here is my understanding.

  • Step 1: When you say Integer counter = 0;what you're actually doing is
    Integer counter = new Integer(0); Here you created an Integer object whose value is 0 and counter is reffering to it.
  • Step 2: Integer test = counter;

    Now test is also referring to the same Integer object we created in step 1.

  • Step 3: Here comes the tricky part. When you do counter++; in your main method, Java Auto-boxing and Auto-unboxing features are implementing the below code for you.

    counter = Integer.valueOf(counter.intValue() + 1);

As Integer class is immutable in Java, when the value is incremented from 0 to 1, the valueOf() method is creating a new Integer object and storing the new value 1 in it instead of changing the old object's value (See below for Java's valueOf() method implementation). As you're referring the new object with counter, it de-referenced the old Integer object whose value is 0. But the reference variable test is still holding the old Integer object. This is the reason test printing the old value.

Java's valueOf() method from library class Integer

638     public static Integer More ...valueOf(int i) {
639         assert IntegerCache.high >= 127;
640         if (i >= IntegerCache.low && i <= IntegerCache.high)
641             return IntegerCache.cache[i + (-IntegerCache.low)];
642         return new Integer(i); //See, new object is created here.
643     }

See below for detailed diagrammatic explanation.

Solid line implies reference variable is still holding the object.

Dotted line implies reference variable is no more holding the object.

enter image description here

Prudhvi
  • 2,276
  • 7
  • 34
  • 54
1

test doesn't reference counter. It has the same initial value. int is a primitive.

zubergu
  • 3,646
  • 3
  • 25
  • 38
0

test is not a pointer to counter: you are setting its value to be equal to counter initially, but any subsequent changes to counter will not be reflected in the value of test.

If you want to have two references to the same mutable value, you can use something like AtomicInteger:

static AtomicInteger counter = new AtomicInteger(0);
static AtomicInteger test = counter;
public static void main(String args[]) {
     counter.incrementAndGet();
     System.out.println("counter: " + counter);
     System.out.println("test: " + test);
}

Output:

counter: 1
test: 1
Andy Turner
  • 137,514
  • 11
  • 162
  • 243
-2

You need to distinguish between a primitive and a referenced-object. Integer are not primitive 'per-se' but they have special properties due to 'boxing'. What you have is a primitive due to intValue() hence it gets the initial value (it has no more relation to the counter).

Well...for the record 'downgraders': the OP has changed his fields from 'int' to 'Integers' and therefore my initial answer was incorrect.

Community
  • 1
  • 1
adhg
  • 10,437
  • 12
  • 58
  • 94