5 ms·
Boxing with Java
- edwinnathaniel 15y agoThis is because Java cache the Integer objects from -128 to 127. So while it is correct that you should probably be more careful when dealing with Autoboxing (or don't use it at all if you can...), there's one more layer deep that the article did not touch: the actual implementation of Java. http://www.docjar.com/html/api/java/lang/Integer.java.html http://www.docjar.com/html/api/java/lang/Integer.java.html Observe the IntegerCache inner class in particular: "Cache to support the object identity semantics of autoboxing for values between -128 and 127 (inclusive) as required by JLS. The cache is initialized on first usage. The size of the cache may be controlled by the -XX:AutoBoxCacheMax=<size> option."
- eropple 15y agoIIRC, this cache only works if you use Integer.valueOf instead of the constructor. (I could be misremembering, but the reason for that seems obvious to me.)
- masklinn 15y ago> the reason for that seems obvious to me. That Java's semantics force new object creation on constructor call, it's not possible to do otherwise (as opposed to, say, JavaScript, Python or Ruby in which object creation can be overridden and the "constructor" work like a factory methods, when it isn't one outright) (which it is in Python and Ruby)
- eropple 15y agoYes, exactly.
- masklinn 15y ago> the actual implementation of Java. > [...] > as required by JLS. If it's required by JLS, then it has to do with Java the language, it's got nothing to do with "the actual implementation of Java": this behavior is part of the semantics of java-the-language.
- edwinnathaniel 15y agoWhat I'm trying to say is that the article did not go deeper to the JLS level :D
- Someone 15y agoFor those wondering: http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.7 http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#...: "If the value p being boxed is true, false, a byte, or a char in the range \u0000 to \u007f, or an int or short number between -128 and 127 (inclusive), then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2. Ideally, boxing a given primitive value p, would always yield an identical reference. In practice, this may not be feasible using existing implementation techniques. The rules above are a pragmatic compromise. The final clause above requires that certain common values always be boxed into indistinguishable objects. The implementation may cache these, lazily or eagerly. For other values, this formulation disallows any assumptions about the identity of the boxed values on the programmer's part. This would allow (but not require) sharing of some or all of these references. This ensures that in most common cases, the behavior will be the desired one, without imposing an undue performance penalty, especially on small devices. Less memory-limited implementations might, for example, cache all char and short values, as well as int and long values in the range of -32K to +32K." When I first heard about that, I wondered why they would specifically specify that range in the language standard. Wouldn't it be better to describe the desired performance, and leave it at "implementations may choose to have boxing a given primitive value p, always yield the same reference, either for all values, or for some values"? Even if Sun's implementation used that trick to get sufficient performance in some part of the JDK, I do not think they should force everybody else to use it. Also, the way I read that first paragraph is that two primitive values p and q of the same type with identical small values may still get boxed to different references. I doubt anybody would implement it that way, though, and the second paragraph seems to be in disagreement with that by speaking of "certain common value_s_".
- funkah 15y agoYuck, what a nightmare. 1000 should equal 1000.
- RobAtticus 15y agoIt does, but their memory locations need not be the same. Making the == operator act differently just because the Objects in question are boxed version of primitives would probably be more of a nightmare than having the == operator act consistently. Perhaps a better solution would be a compiler warning so these mistakes can be identified quicker.
- morsch 15y agoArguably making the == operator mean two different things -- equal in value and equal in reference -- is the problem to start with. I'd prefer it if == was a value comparison in all cases, and reference comparison were mapped to === or something. I guess the extra verbosity doesn't get a lot of fans here...
- extension 15y agoThis is what operator overloading is for. If equals() should always be used to compare objects then == should call it.
- wiradikusuma 15y agoJava doesn't support operator overloading.
- masklinn 15y agoDoesn't java support privileged operator overloading for `+`? (privileged in that it's only supported for types baked into the runtime itself, much like generics in Go)
- mkaufmann 15y agoWhile one problem the blog post describes is valid, I think the authors comes to the wrong conclusion. The problem is that the method is implemented in such a way that it uses Integer objects which are different from the native integer types. Objects have very clear semantics concerning the == operator. It checks whether the object identity is the same (alas it is the same object). There is nothing special about it, thats also the reason why you can't compare two strings with == and this is s.th. I think every Java developer learns within the first days/weeks (often by first doing it wrong, I don't claim that this is intuitive). So in this light the correct solution, which the author even does not mention anymore in the end, would be for the method to use the a.equals(b). Everything would work. The point of the author that a team should agree on using either one or the other is nonesene, because in some situations there is no choice (e.g. HashMaps only work with objects). Also there is no real problem, because whoever implemented the method know what he gets and should have implemented it using the equals method. So in reality this should not be fixed with creating seperate Integer instances but with fixing the method itself. As a last comment, there is one pitfall to watch out for with autoboxing. When you use the "int" type in your code and call a method which returns an "Integer" and you compare with == you can get wrong results. I think of this as a real problem, because often you know that a method will return a number but you don't expect it to be returned as Integer. Or even worse between versions of the api the method is changed from returning int to Integer and you don't even notice because it compiles. But I think this happens very rarely and personally I always return numbers as native types. PS: But I can understand that it is sometimes confusing that the code is working in some cases and not working in others, when it should never work! If you want to get a really good understanding of the semantics of the Java language I would advise to read ( http://java.sun.com/docs/books/effective/ http://java.sun.com/docs/books/effective/ )
- powatom 15y agoThe author ( me :P ) mentions that using a.equals(b) is the correct solution right at the beginning of the post. Unfortunately this problem will continue to occur as long as autoboxing exists, so I think it's a valid idea to simply enforce a rule across your team that says 'Here's how we're going to avoid autoboxing problems'. I intended this post to be more of an illustration of what autoboxing does. With regards to your comment that the solution is not to create separate integer instances - I was attempting to show that this is a possible solution to autoboxing headaches rather than 'the correct' solution for testing integer equality, because the objects are not cached. Sometimes you want to use == for valid reasons, the problem I had was because I wasn't vigilant enough in checking my own code and used == when I shouldn't have used it in the first place. Perhaps this post could have been written more clearly - but as it happens, you're spot on. The examples at the end of the post were intended to be potential solutions to autoboxing headaches in general, rather than a solution for my specific problem :)
- efsavage 15y agoAutoboxing was the worst thing ever added to Java.
- maxs 15y agoThis is an example of a bug that FindBugs would catch ( http://findbugs.sourceforge.net/ http://findbugs.sourceforge.net/ ). FindBugs is a static source analysis tool for Java. It's free and open source, no reason not to use it on your codebase :).
- powatom 15y agoAgree 100%, I'm just forgetful and lazy (a winning combination) :P I need to get it set up to run automatically!
- spullara 15y agoUse .equals() like you're supposed to with objects. If you aren't going to use the primitive types that is really the only good option.
- morsch 15y agoI think making auto-Boxing generate a warning is a bit over the top, but it's worth it to enable syntax highlighting for it. It just draws your eyes to it during debugging. I think mine is set to italicize all instances of auto-boxing. And of course, avoid it where it doesn't smell good.