Java Language Spec 5.1.7:
If the value p being boxed is true,
false, a byte, a char in the range
\u0000 to \u007f, or an int or short
number between -128 and 127, then let
r1 and r2 be the results of any two
boxing conversions of p. It is always
the case that r1 == r2.
and:
Discussion
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 characters and shorts, as
well as integers and longs in the
range of -32K - +32K.
So, in some cases == will work, in many others it will not. Always use .equals to be safe since you cannot grantee (generally) how the instances were obtained.
If speed is a factor (most .equals start with an == comparison, or at least they should) AND you can gurantee how they were allocated AND they fit in the above ranges then == is safe.
Some VMs may increase that size, but it is safer to assume the smallest size as specified by the langauge spec than to rely on a particular VM behaviour, unless you really really really need to.