Integer 128 != Integer 128 ??

Integer 128 != Integer 128 ??

Post by phi » Wed, 13 Oct 2010 18:59:05


Hello all

Can anyone tell me, what is happening in the code below (JSDK 1.5.0,
tested on windows and on linux)?

Why ist 127 == 127, but 128 != 128?

Somehow the == Operator has a problem with the Integer-Class(?) or
is it the class-loader, which stores the bytes differently in its
constant pool?


Thx



code:

Integer a127, b127, a128, b128;
a127 = 127;
b127 = 127;
a128 = 128;
b128 = 128;

if(a127 == b127) {
System.out.println("127 ok"); // This happens and is ok.
}
if(a128 == b128) {
System.out.println("128 ok"); // this does NOT happen! Hence
my question.
}
 
 
 

Integer 128 != Integer 128 ??

Post by Thomas Por » Wed, 13 Oct 2010 21:13:15

According to phi < XXXX@XXXXX.COM >:

Instances of "Integer" are not necessarily unique. An Integer instance
is an object; you can think of your 'a128' and 'b128' variables as
pointers to a chunk of RAM. That chunk of RAM wraps around an 'int'
value.


Java 5 implements 'auto-boxing', a syntaxic feature which tries to
automatically fill the gap between the 'int' type (the 32-bit signed
integer) and the 'Integer' type (the class where every instance
contains an 'int' value). When you write this:

Integer x = 128;

what actually gets compiled is:

Integer x = Integer.valueOf(128);

where Integer.valueOf() is a static method which returns an Integer
instance containing the provided 'int' value. Integer.valueOf() may
return the same instance twice, or not; in practice, the implementation
of Integer.valueOf() often caches instances for small integers, e.g.
those from -128 to 127. For other values, it performs a simple 'new
Integer(val)' and returns that, hence a new instance every time. This is
what you observe.


When you use '==' on two 'Integer' values, you are comparing the
pointers (the "references" in Java terminology). If two pointers are
equal then they point to the same instance, wrapping around a unique
value. But if two pointers are distinct, it just means that they point
to distinct instances, _not_ that those instances contain distinct 'int'
values.

Operators are not overloaded in Java (well, at least not to that point).
If you want a numerical comparison then you have to get the numbers
themselves, not the wrappers:

Integer a128 = 128;
Integer b128 = 128;
if (a128 == b128) {
/* you have compared the pointers */
}
if (a128.intValue() == b128.intValue()) {
/* you have compared the numerical values */
}

Auto-boxing blurs the line a bit between class instances and plain
integers, but that does not make integers objects in their own right.
The point of auto-boxing is to ease the syntaxic use of integers as keys
or values in collections (List, Map...).


--Thomas *** in

 
 
 

Integer 128 != Integer 128 ??

Post by Jukka Laht » Wed, 13 Oct 2010 21:15:23

phi < XXXX@XXXXX.COM > writes:


You shouldn't use the == to compare values of Integers or other objects,
use it only for numerical primitives (or testing whether an object is
null).
The operator tests whether both sides of it point to the same object,
which is not always the case even when their values are same.
With Integers and other subclasses of Number, use the equals method for
testing equality and the compareTo method if you need to know not only
equality but also which one is bigger.
See the javadocs for Integer.

..

So, replace this with
if (a127.equals(b127)) {


and replace this with
if (a128.equals(b128)) {

and you get what you probably meant.

--
Jukka Lahtinen
 
 
 

Integer 128 != Integer 128 ??

Post by Eric Sosma » Wed, 13 Oct 2010 21:27:58


This is one of the reasons I think "auto-boxing" was a bad
idea, and remains a bad idea.

Here's what happens: `127' is an `int' (a "primitive value"),
but `a127' and `b127' are `Integer' references. In the Old Days,
Java would have rejected the attempt to assign an `int' value to
an `Integer' reference, because `int' and `reference' are different
types. It would have been necessary to write something like

a127 = Integer.valueOf(127);
or
b127 = new Integer(127);

But a few years ago, somebody thought it would be a convenience
if Java did this and a few related things automatically. Now, when
you write the once-forbidden `a127 = 127' Java silently rewrites it
as `a127 = Integer.valueOf(127)' and pats itself on the back for being
so clever and helpful. After this silent rewriting, you've got

Integer a127, b127, a128, b128;
a127 = Integer.valueOf(127);
b127 = Integer.valueOf(127);
a128 = Integer.valueOf(128);
b128 = Integer.valueOf(128);

Next, we get into a fiddly implementation detail of the Integer
class. Somebody noticed that many programs using Integer objects
tended to use a lot of the smaller values over and over: There were
lots of zeroes and ones and fives, and comparatively few twenty-seven
thousand eight hundred fifty-twos. And it was sort of a shame to fill
up memory with this zero, that zero, the other zero, yet another zero,
and so on, when in most situations you really didn't need all these
zeroes to be distinct. So they wrote the Integer.valueOf() method to
allocate a few Integers with smallish values and to use them whenever
it can, instead of minting a brand-new Integer object every time. If
your desired value is "small enough" you wind up re-using the same
Integer object, while if it isn't you get a new Integer. And it
turns out that 127 is "small enough" but 128 isn't, so now your code
behaves something like

Integer a127, b127, a128, b128;
a127 = Integer.private_preallocated_Integer_127;
b127 = Integer.private_preallocated_Integer_127;
a128 = new Integer(128);
b128 = new Integer(128);

There are three objects in play here: a127 and b127 both refer to
one of them, while a128 and b128 refer to the other two. These latter
Integer objects both have the numeric value 128, but are distinct
objects -- and when you ask `a128 == b128' you are asking "Do a128
and b128 refer to the same object?" and the answer is "No," just as
the answer to `new String("hello") == new String("hello")' is "No."

If you had tried

if (a128.intValue() == b128.intValue()) ...
or
if (a128.equals(b128)) ...

Java's misguided attempt to be helpful would not have given you so
much trouble.

--
Eric Sosman
XXXX@XXXXX.COM
 
 
 

Integer 128 != Integer 128 ??

Post by phi » Wed, 13 Oct 2010 21:52:57


Thanks

I know, what I should do in this case and agree fully.
The original Question came up studiing for the "Oracle certified
Professional".

greets

phi
 
 
 

Integer 128 != Integer 128 ??

Post by phi » Wed, 13 Oct 2010 21:57:50


Thanks a lot

For others: The anwer of Eric Sosman to my original question
clarifies the fact in deeper detail.

greetig

phi
 
 
 

Integer 128 != Integer 128 ??

Post by phi » Wed, 13 Oct 2010 22:00:41

n 12.10.2010 14:27, Eric Sosman wrote:


Thanks
After your explanation I had a look at the "valueOf()" function in
the Integer class, which opened my eyes fully:


public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}


Thanks to all and greets from switzerland

phi
 
 
 

Integer 128 != Integer 128 ??

Post by phi » Wed, 13 Oct 2010 22:10:53


thanks all.

I have seen it now in the Integer-Class (in the valueOf()-method).
For me, this question is solved.

greetings
 
 
 

Integer 128 != Integer 128 ??

Post by Mike Schil » Thu, 14 Oct 2010 00:22:42


As well as doing other C#-like things, some of which are great (the enhanced
for-loop) and some not (auto-boxing).
 
 
 

Integer 128 != Integer 128 ??

Post by Peter Duni » Thu, 14 Oct 2010 00:58:31


Though, to be fair, the real problem here is not the auto-boxing, but
rather the poor implementation of auto-boxing combined with an unhelpful
optimization.

In .NET (C#), autoboxing doesn't do any sort of interning on values like
Java appears to. You have an integer stored in an object reference, it
gets boxed in a new object instance, always.

In .NET, you also have value types. So things like integers don't need
to be boxed nearly as often as they do in Java. In particular, .NET
generics allow for value types like integer to be stored directly in
fully reified integer-specific classes when using generics.

You would still have the problem of reference equality in C# as one has
in Java, but it doesn't come up as much, and it's always consistent when
it does. Also, since C# supports operator overloading, C# programmers
are generally (though of course not always) more aware of the subtleties
between using the == operator and calling the Equals() method.

Ironically, in this one way Java _could_ have worked better than C#. C#
auto-boxing just boxes into a System.Object type. C# doesn't have
reference type versions of value types like Java does (i.e. no Integer
class to go with "int", no Boolean to go with "boolean", etc.). If Java
had operator overloading, then the Integer class could have overloaded
the == operator, allowing an autoboxed int to be compared with another
one successfully even using the == operator.

In other words, while Java does seem to have a similar idea of
auto-boxing as that found in .NET/C#, it would be a mistake to judge the
behavior of the feature in .NET based on the Java implementation. As
similar as they are in some ways, the two are very different in some
other important ways.

Pete
 
 
 

Integer 128 != Integer 128 ??

Post by Roedy Gree » Thu, 14 Oct 2010 02:17:18

On Tue, 12 Oct 2010 11:59:05 +0200, phi < XXXX@XXXXX.COM > wrote,
quoted or indirectly quoted someone who said :


you meant to write if (a128.equals( b128) ). What you are checking is
are they pointing to the same Integer object.

127 works because of an optimisation to create ints 0..127 with
preformed Integer objects. Incidentally the objects are the same, not
just the values.

--
Roedy Green Canadian Mind Products
http://www.yqcomputer.com/

You encapsulate not just to save typing, but more importantly, to make it easy and safe to change the code later, since you then need change the logic in only one place. Without it, you might fail to change the logic in all the places it occurs.
 
 
 

Integer 128 != Integer 128 ??

Post by Joshua Cra » Thu, 14 Oct 2010 04:50:25


The primary intent of autoboxing, I think, was the introduction of
generics. Since generics now allowed you to remove casts from retrieving
values from collections, the next logical step was to sugar the
retrieval of primitive values, to let a List<Integer> "feel" like an int[].

The original problem, I think, remains Java's deplorable decision to
separate out primitive and reference types.

--
Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth
 
 
 

Integer 128 != Integer 128 ??

Post by Eric Sosma » Thu, 14 Oct 2010 10:49:15


Don't misunderstand me: I am not grumpily opposed to everything
that's been added to Java. The auto-boxing misfeature is the target
of my scorn, not the other stuff.

Hey, here's another example that floated through this newsgroup
not so long ago: Somebody had a multi-threaded thingummy, and he
wanted to maintain a thread-safe counter of something. So he wrote
(paraphrased from inexact memory):

class Whatever {
// ...
private static Integer count = 0;
static void incrementCount() {
synchronized(count) {
count++;
}
}
// ...
}

... and then he found that it wasn't working properly. It's my
belief that auto-boxing was entirely responsible for this error:
without auto-boxing, the compiler would have prevented him from
making it in the first place. To put it another way, auto-boxing
silenced a compile-time error and replaced it with a hard-to-debug
run-time error; in my book that's not an improvement.

"Auto-boxing" means "I'm punching myself."

--
Eric Sosman
XXXX@XXXXX.COM
 
 
 

Integer 128 != Integer 128 ??

Post by Peter Duni » Thu, 14 Oct 2010 12:25:21


If your example was:

class Whatever {
// ...
private static int count = 0;
static void incrementCount() {
synchronized(count) {
count++;
}
}
// ...
}

hen it would be plausible. :) Integer is a reference type and should
not require boxing for use in the "synchronized" statement.

And yes, even in C#, locking on a value type is a very bad idea. :)

Pete
 
 
 

Integer 128 != Integer 128 ??

Post by Daniel Pit » Thu, 14 Oct 2010 12:37:08


Its not the synchronized statement that boxing affected, its the ++
statement. count is a *different* reference every time "incrementCount"
gets called, and therefore two threads may see different values of count
inside the synchronize block. They will indeed become less likely to
properly synchronize over time.

synchronizing on a primitive is not valid, so the compiler *would* have
complained.

For posterity, the correct approach is to use an AtomicInteger.

--
Daniel Pitts' Tech Blog: < http://www.yqcomputer.com/ ;