Why aren't Integers cached in Java?

前端 未结 15 1504
無奈伤痛
無奈伤痛 2020-11-27 05:27

I know there are similar posts on the topic, but they don\'t quite address my question. When you do:

Integer a = 10;
Integer b = 10;
System.out.println(\"a =         


        
相关标签:
15条回答
  • 2020-11-27 05:44

    It's because you're using the new statement to construct the objetcs.

    Integer a = Integer.valueOf(10);
    Integer b = Integer.valueOf(10);
    System.out.println("a == b: " + (a == b));
    

    That will print out true. Weird, but Java.

    0 讨论(0)
  • It should be very clear that caching has an unacceptable performance hit -- an extra if statement and memory lookup every time you create an Integer. That alone overshadows any other reason and the rest of the agonizing on this thread.

    As far as responding "correctly" to ==, the OP is mistaken in his assumption of correctness. Integers DO respond correctly to == by the general Java community's expectation of correctness and of course by the specification's definition of correctness. That is, if two references point to the same object, they are ==. If two references point to different objects, they are not == even if they have the same contents. Thus, it should be no surprise that new Integer(5) == new Integer(5) evaluates to false.

    The more interesting question is why new Object(); should be required to create a unique instance every time? i. e. why is new Object(); not allowed to cache? The answer is the wait(...) and notify(...) calls. Caching new Object()s would incorrectly cause threads to synchronize with each other when they shouldn't.

    If it were not for that, then Java implementations could totally cache new Object()s with a singleton.

    And that should explain why new Integer(5) done 7 times must be required to create 7 unique Integer objects each containing the value 5 (because Integer extends Object).


    Secondary, Less Important Stuff: One problem in this otherwise nice scheme results from the autoboxing and autounboxing feature. Without the feature you could not do comparisons such as new Integer(5) == 5. To enable these, Java unboxes the object (and does not box the primitive). Therefore new Integer(5) == 5 is converted to: new Integer(5).intValue() == 5 (and not new Integer(5) == new Integer(5).

    One last thing to understand is that autoboxing of n is not done by new Integer(n). It is done internally by a call to Integer.valueOf(n).

    If you think you understand and want to test yourself, predict the output of the following program:

    public class Foo {
      public static void main (String[] args) {
        System.out.println(Integer.valueOf(5000) == Integer.valueOf(5000));
        System.out.println(Integer.valueOf(5000) == new Integer(5000));
        System.out.println(Integer.valueOf(5000) == 5000);
        System.out.println(new Integer(5000) == Integer.valueOf(5000));
        System.out.println(new Integer(5000) == new Integer(5000));
        System.out.println(new Integer(5000) == 5000);
        System.out.println(5000 == Integer.valueOf(5000));
        System.out.println(5000 == new Integer(5000));
        System.out.println(5000 == 5000);
        System.out.println("=====");
        System.out.println(Integer.valueOf(5) == Integer.valueOf(5));
        System.out.println(Integer.valueOf(5) == new Integer(5));
        System.out.println(Integer.valueOf(5) == 5);
        System.out.println(new Integer(5) == Integer.valueOf(5));
        System.out.println(new Integer(5) == new Integer(5));
        System.out.println(new Integer(5) == 5);
        System.out.println(5 == Integer.valueOf(5));
        System.out.println(5 == new Integer(5));
        System.out.println(5 == 5);
        System.out.println("=====");
        test(5000, 5000);
        test(5, 5);
      }
      public static void test (Integer a, Integer b) {
        System.out.println(a == b);
      }
    }
    

    For extra credit, also predict the output if all the == are changed to .equals(...)

    Update: Thanks to comment from user @sactiw : "default range of cache is -128 to 127 and java 1.6 onward you can reset the upper value >=127 by passing -XX:AutoBoxCacheMax= from command line"

    0 讨论(0)
  • 2020-11-27 05:48

    new means new.

    new Object() isn't frivolous.

    0 讨论(0)
  • 2020-11-27 05:48

    A new instance is a new instance, so they are equal in value, but they are not equal as objects.

    So a == b can't return true.

    If they were 1 object, as you ask for: a+=2; would add 2 to all int = 10 - that would be awful.

    0 讨论(0)
  • 2020-11-27 05:52

    Wouldn't it make more sense if all instances of an Integer with a 10 be the same object in memory? In other words, why don't we have "Integer interning" which is similar to "String interning"?

    Because it would be awful!

    First, this code would throw an OutOfMemoryError:

    for (int i = 0; i <= Integer.MAX_VALUE; i++) {
        System.out.printf("%d\n", i);
    }
    

    Most Integer objects are probably short-lived.

    Second, how would you maintain such a set of canonical Integer objects? With some kind of table or map. And how would you arbitrate access to that map? With some kind of locking. So suddenly autoboxing would become a performance-killing synchronization nightmare for threaded code.

    0 讨论(0)
  • 2020-11-27 05:53

    BTW, If you do

    Integer a = 234345;
    Integer b = 234345;
    
    if (a == b) {}
    

    it is possible that this will be true.

    This is because since you didn't use new Integer(), the JVM (not the class code) is allowed to cache its own copies of Integers if it sees fit. Now you shouldn't write code based on this, but when you say new Integer(234345) you are guaranteed by the spec that you will definitely have different objects.

    0 讨论(0)
提交回复
热议问题