Why doesn't Integer have a setValue(int i), and is there a way of changing its value.

J

Joseph Dionne

Sudsy said:
I've never heard of such a rule. According to the javadocs for
Object#hashCode:

Objecte.hashCode does not work like Interger.hashCode.

Integer provides it's own hashCode method that returns the value. This
allows you to put an Integer object into a list and find it again via
another Integer object.

The Object.hashCode method will produce two different hash values for
two Integer objects even if each Integer object is equal.

Integer Int1 = new Integer(123);
Integer Int2 = new Integer(123);

thus Int1.hashCode() == Int2.hashCode() and Int1.equals(Int2) are true

However a replacement Integer class that does not implement hashCode,
relying on Object.hashCode will result in two unique hash values.


Example; (uncomment the Int.equals method to see the difference)

public class tJava
{
public static void main(String[] args) throws Exception
{
Object Int1 = new Integer(123);
Object Int2 = new Integer(123);

if (Int1.hashCode() == Int2.hashCode())
System.out.println("hashCode are equal");
else
System.out.println("hashCode are unequal");

if (Int1.equals(Int2))
System.out.println("they are equal");
else
System.out.println("they are unequal");

if (((Object)Int1).hashCode() == ((Object)Int2).hashCode())
System.out.println("hashCode are equal");
else
System.out.println("hashCode are unequal");

Int1 = new Int(123);
Int2 = new Int(123);

if (Int1.hashCode() == Int2.hashCode())
System.out.println("hashCode are equal");
else
System.out.println("hashCode are unequal");

if (Int1.equals(Int2))
System.out.println("they are equal");
else
System.out.println("they are unequal");

if (((Object)Int1).hashCode() == ((Object)Int2).hashCode())
System.out.println("hashCode are equal");
else
System.out.println("hashCode are unequal");
}
}

class Int
{
private int value;

public Int(int v) { value = v; }

public int intValue() { return(value); }

// public boolean equals(Object o)
// {
// if (o instanceof Int) return(value == ((Int)o).value);
// return(false);
// }
}
 
G

George W. Cherry

Alex Hunsley said:
natG said:
Can you please explain "safer"? Do I practice SAFE Java<g>?
Seriously, safer in what respect?
Thanks
-nat

[top posting fixed]

It's harder to make coding mistakes when wrappers like Integer are
immutable. And with such a simple object, it's just as easy to make a
new one as it would be to call Integer.setValue().
(By coding mistakes I refer to situations where, for example, you change
an Integer object that is also referenced somewhere else, which will
then run into problems because the value has changed etc.)

(An added benefit is that the system can cache existing Integer objects
- no matter how many times you call new Integer(1), there is only one in
existence (I would presume).

Can you please not top post, btw? It makes threads easier to follow if
you bottom post.

http://www.ptialaska.net/~kmorgan/nquote.html
http://www.zedtoo.demon.co.uk/jcode/basic.html
http://www.netmeister.org/news/learn2quote2.html#ss2.3




alex

Yes, top-posting is bad "netiquette".

George
 
N

natG

Alex Hunsley said:
natG said:
Can you please explain "safer"? Do I practice SAFE Java<g>?
Seriously, safer in what respect?
Thanks
-nat

[top posting fixed]

It's harder to make coding mistakes when wrappers like Integer are
immutable. And with such a simple object, it's just as easy to make a
new one as it would be to call Integer.setValue().
(By coding mistakes I refer to situations where, for example, you change
an Integer object that is also referenced somewhere else, which will
then run into problems because the value has changed etc.)

(An added benefit is that the system can cache existing Integer objects
- no matter how many times you call new Integer(1), there is only one in
existence (I would presume).

Can you please not top post, btw? It makes threads easier to follow if
you bottom post.

http://www.ptialaska.net/~kmorgan/nquote.html
http://www.zedtoo.demon.co.uk/jcode/basic.html
http://www.netmeister.org/news/learn2quote2.html#ss2.3




alex

SAFE; that is a great explanation, plus the caching theory, it makes sense.
I apologize about the posting, and am still not clear. Is it better this way where
the quoted stuff goes first?
Is this accepted newsgroup practice? First I heard of it, but am willing to
oblige.
-nat
 
N

natG

Bent C Dalager said:
Two cases spring immediately to mind.

If you use instances of the class as keys in a Map, or you have them
in a Collection that you expect to always be sorted, then immutability
guarantees that your sorting won't inadvertantly get screwed up by
someone calling a setter at inopportune times. With immutable keys,
the only thing that can mess with your sorting is when the
Collection's setters are called. The alternative to immutability would
be for the class to fire events whenever you changed something and the
Collections classes to be sensitive to such events and be able to
auto-resort themselves, but this gets real messy real quick.

VERY interesting. But it also scares me because I have quite a few Comparable
classes that have setters, and are sitting in Maps.
I never thought of any consequense of using the setters. Although, the real issue
would be I guess, with a TreeMap or other that mainatains a live sort, without
call to Collections.sort();
Also, for String, allowing it to be changed at any time would be a
security hazard when used within security-sensitive library
functions. As an example, I could send in username "guest" and
password "guest" as Strings to some function and then at some later
time, after I had been authenticated, change the contents of the
username String to "root". Unless the library was carefully written,
this has the potential of being a security problem. As things are, the
fewer of these pitfalls exist, the better.

Enlightening points, thanks.
How many of your methods take some object instance as parameter, hang
on to it and expect it not to change thereafter? Any that do are
vulnerable to malfunction when the instance gets mutated from the
outside.

Never thought of it.
[top posting fixed]

Thank you :)

Same here said:
Cheers
Bent D
-nat
 
N

natG

Sudsy said:
I've never heard of such a rule. According to the javadocs for
Object#hashCode:
"This is typically implemented by converting the internal address of
the object into an integer, but this implementation technique is not
required by the JavaTM programming language."

Sounds good enough for me! As to the equals, only an implementation
can decide what equality means. The toString method is often used to
generate something like classname@hashCode, although it can also be
coded to dump the internal object state. In the simple case (this
one) we can just return the value, just like Integer#toString does.

Here is the rule:
http://java.sun.com/docs/books/tutorial/java/javaOO/objectclass.html
Minor quote from that page: "The equals/hashCode are listed together as they must
be overridden together. "

-nat
 
N

natG

Marco said:
That's true (except the bit about toString(). toString()
isn't related to equals() or hashCode()).
If you change the semantics of equals(), you should
override hashCode() too. If a.equals(b) is true, then
a.hashCode() == b.hashCode() must also be true.

This sums it up, in one clear rule. Thanks. Btw, I think there is a little error
in your example, but I get the point. TA.
If not, and you store these objects in a hash table ( e.g.
java.util.HashMap, java.util.HashSet or java.util.Hashtable),
they'll be hashed and coerced into different buckets. In
other words, they'll be treated as separate keys even though
your definition of equals() says they're identical.

Example:
Suppose you define a class like this, defining specialized
equals() semantics without a matching hashCode()...

class IntegerWrapper extends Object {
int value;
public IntegerWrapper(int value) {
this.value = value;
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if ( obj == null || this.getClass() != obj.getClass() )
return false;
IntegerWrapper other = (IntegerWrapper) obj;
return this.value == other.value;
}
}

...and then use instances of this class in a hash table,
like this...

class Test {
public static void main(String[] args) {
HashMap hm = new HashMap();
hm.put( new IntegerWrapper(5), "hello" );
hm.put( new IntegerWrapper(5), "goodbye" );
Object obj = hm.get( new IntegerWrapper(5) );
System.out.println(obj);
}
}

What do you think will be printed out? "hello", "goodbye"
or null? The answer is null, even though
IntegerWrapper.equals() defines these 3 instances as equal:

new IntegerWrapper(5)
new IntegerWrapper(5)
new IntegerWrapper(5)

Marco
 
N

natG

Jon Skeet said:
1500 times per hour is absolutely nothing. I've just written a program
to generate 1500 of them 100,000 times - and it took about 3 seconds.
Just don't worry about it at all.

You are 100% right. The point is moot.
On a 1.6ghz xpPro system, I just tested generating 7,654,321 new Integer objects.
It took 297 milliseconds, and consumed around 33KB.

-nat
 
A

Adam Jenkins

Bent said:
I believe the reason is that for a wide range of uses, immutable is
safer. As I recall, Sun is very clear about this when it comes to the
String class, and I suspect much of the same reasoning lies behind the
primitive-wrappers.

Making java.lang.String be immutable makes it possible to intern string
constants, and share string and substring data. I always figured that
was the main reason for String being immutable. This doesn't apply to
the Number classes, though.

As for safer, I suppose it makes it so a programmer can't go changing a
hash key behind the hashtable's back or something similar if one of
these immutable classes is being used as the key. But it seems pretty
arbitrary and inconsistent to decide that just these dozen or so classes
are immutable. Why shouldn't java.util.Date, or org.w3c.dom.Node be
immutable too? In some functional languages like Haskell, all variables
can only be assigned to once. There are a lot of strong benefits to a
strictly side-effect free language, but you don't get any of those
benefits by just making some arbitrary handful of classes immutable.

Adam
 
H

Harald Hein

Joseph Dionne said:
Integer provides it's own hashCode method that returns the value.
This allows you to put an Integer object into a list and find it
again via another Integer object.

Which will be a problem for an implementation of a mutable MyInteger.
If you use such a MyInteger as a key in a hashtable, and then change
the contents, what to do with the hash?

Maybe it wasn't such a bad idea of the language designers to make
Integer and the like imutable.
 
D

Doug Pardee

natG said:
It's something I considered but put it off because of other
uses of this Integer that will force me to duplicate quite a
few Integer methods. For starters: hashCode, equals,
compareTo, toString, and then some.

EVIL!

A "value type" is one whose objects are known by their values. Integer
is a fine example of that. You don't really care *which* "2" you're
dealing with... "2" is "2". This is a really important property,
because it means that a copy is every bit as good as the original,
which in turn means that copies can be sent to other systems and
(critically important) copies can be saved on disk.

The equals, hashCode, and compareTo methods are associated with value
types, because they use the value of the object as the object's
identity (rather than using the object's address). These should only
be overridden for value types; the default implementations for equals
and hashcode use the object's address and are the correct
implementations for non-value types.

Value types must not be both aliasable and mutable. Java's primitive
types (int, char, boolean, float, etc.) are non-aliasable. Java's
non-primitive value classes are always aliasable, so they MUST be made
immutable.

In your case, you are not trying to create a value type, but rather a
mutable container type. Overriding equals, hashCode, and compareTo is
a bad idea because that will violate the defined behavior of those
methods, and so some of the Java library will break when used with
your class.

You are free to add new methods of your own, called perhaps "isEqual"
and "comparedWith", that don't have any predefined semantics.

(None of this has anything to do with toString, and overriding
toString is a great idea.)
 
C

Chris Riesbeck

Sudsy said:
I've never heard of such a rule. According to the javadocs for
Object#hashCode:

"This is typically implemented by converting the internal address of
the object into an integer, but this implementation technique is not
required by the JavaTM programming language."

The key line is in the bullet points above this quote:

"If two objects are equal according to the equals(Object) method, then
calling the hashCode method on each of the two objects must produce
the same integer result."
http://java.sun.com/j2se/1.3/docs/api/java/lang/Object.html#hashCode()

So if you change the rules for equals(), you should change hashCode()
to match. Otherwise, your object won't work correctly when saved in
hashtable-based containers like HashSet and HashMap.

See Bloch's Effective Java for how to define hashCode().
 
D

Doug Pardee

Sudsy said:
I've never heard of such a rule. According to the javadocs for
Object#hashCode:

According to those very JavaDocs:

"If two objects are equal according to the equals(Object) method,
then calling the hashCode method on each of the two objects must
produce the same integer result."

Since the default implementation of hashCode will prevent any two
Objects from having the same hashCode value*, the only override of the
"equals" method that will preserve the contract is "return false".
That seems rather an unlikely implementation**, so it is fair to say
that any override of "equals" should be accompanied by an override of
"hashCode".

* The JavaDocs say "as much as is reasonably practical", but the
possibility that in some JVMs there is a chance that two Objects might
have the same default hashCode does not change the point being made.

** It's not only unlikely, it violates the "reflexive" specification
for "equals": that x.equals(x) returns true.
 
N

natG

Bent C Dalager said:
Two cases spring immediately to mind.

If you use instances of the class as keys in a Map, or you have them
in a Collection that you expect to always be sorted, then immutability
guarantees that your sorting won't inadvertantly get screwed up by
someone calling a setter at inopportune times. With immutable keys,
the only thing that can mess with your sorting is when the
Collection's setters are called. The alternative to immutability would
be for the class to fire events whenever you changed something and the
Collections classes to be sensitive to such events and be able to
auto-resort themselves, but this gets real messy real quick.

Question: Suppose:
Integer a = new Integer(10);
Integer b = new Integer(20);
Integer c = new Integer(30);
TreeMap tm = new TreeMap();
tm.put(a);
tm.put(b);
tm.put(c);
And then:
b = new Integer(60);
Now, I assume that the second Integer added to the Map, will return an int value
of 60.
If so, what happens to the sort at that point?
-nat
Also, for String, allowing it to be changed at any time would be a
security hazard when used within security-sensitive library
functions. As an example, I could send in username "guest" and
password "guest" as Strings to some function and then at some later
time, after I had been authenticated, change the contents of the
username String to "root". Unless the library was carefully written,
this has the potential of being a security problem. As things are, the
fewer of these pitfalls exist, the better.

How many of your methods take some object instance as parameter, hang
on to it and expect it not to change thereafter? Any that do are
vulnerable to malfunction when the instance gets mutated from the
outside.
[top posting fixed]

Thank you :)

Cheers
Bent D
 
N

natG

Adam Jenkins said:
Making java.lang.String be immutable makes it possible to intern string
constants, and share string and substring data. I always figured that
was the main reason for String being immutable. This doesn't apply to
the Number classes, though.

As for safer, I suppose it makes it so a programmer can't go changing a
hash key behind the hashtable's back or something similar if one of
these immutable classes is being used as the key. But it seems pretty
arbitrary and inconsistent to decide that just these dozen or so classes
are immutable. Why shouldn't java.util.Date, or org.w3c.dom.Node be
immutable too? In some functional languages like Haskell, all variables
can only be assigned to once. There are a lot of strong benefits to a
strictly side-effect free language, but you don't get any of those
benefits by just making some arbitrary handful of classes immutable.

Adam
Agreed. I put it this way. Java does NOT restrict a class which implements
Comparable from using setters to change its key, neither is there a rule by
convention. If so, why are the wrappers different? But there are other
answers/reasons pointed out elsewhere in this thread, and am satisfied with
those. Very much so.
Thank you all;
-nat
 
N

natG

Harald Hein said:
Which will be a problem for an implementation of a mutable MyInteger.
If you use such a MyInteger as a key in a hashtable, and then change
the contents, what to do with the hash?

Yes..But if you change a immutable Integer in a Map, via = new Integer(int)...
same argument.
-nat
 
J

Joseph Dionne

Harald said:
:




Which will be a problem for an implementation of a mutable MyInteger.
If you use such a MyInteger as a key in a hashtable, and then change
the contents, what to do with the hash?

Maybe it wasn't such a bad idea of the language designers to make
Integer and the like imutable.

I disagree. For example, if I add several MyInteger (that has
implemented the equals() and hashCode() methods) objects, then receive
some external input that is used to find a specific MyInteger, I would
create a new MyInteger object the the search value, look into the
Container, i.e. HashSet, etc, using the new MyInteger object. If the
object is found, I would update the object found.

Now at a later time, the altered MyInteger is to be changed, the same
process as above is performed, and since the new temporary MyInteger
object equals() the modified MyInteger object in the Collection, I will
find the MyInteger I altered previously.

Of course, for sanity, one would need to insure the new value does not
already exist in the Collection before altering the search "key" value.
 
N

natG

Doug Pardee said:
EVIL!

A "value type" is one whose objects are known by their values. Integer
is a fine example of that. You don't really care *which* "2" you're
dealing with... "2" is "2". This is a really important property,
because it means that a copy is every bit as good as the original,
which in turn means that copies can be sent to other systems and
(critically important) copies can be saved on disk.

The equals, hashCode, and compareTo methods are associated with value
types, because they use the value of the object as the object's
identity (rather than using the object's address). These should only
be overridden for value types; the default implementations for equals
and hashcode use the object's address and are the correct
implementations for non-value types.

Value types must not be both aliasable and mutable. Java's primitive
types (int, char, boolean, float, etc.) are non-aliasable. Java's
non-primitive value classes are always aliasable, so they MUST be made
immutable.

In your case, you are not trying to create a value type, but rather a
mutable container type. Overriding equals, hashCode, and compareTo is
a bad idea because that will violate the defined behavior of those
methods, and so some of the Java library will break when used with
your class.

You are free to add new methods of your own, called perhaps "isEqual"
and "comparedWith", that don't have any predefined semantics.

(None of this has anything to do with toString, and overriding
toString is a great idea.)

Thank you for clarifying value-type versus non-value types. Although I have
differentiated these, I didn't realize there is an official lingo and required
practice for one versus the other. I do not understand however, the paragraph you
wrote regarding aliasable and mutuable.

-nat
 
V

Virgil Green

natG said:
Question: Suppose:
Integer a = new Integer(10);
Integer b = new Integer(20);
Integer c = new Integer(30);
TreeMap tm = new TreeMap();
tm.put(a);
tm.put(b);
tm.put(c);
And then:
b = new Integer(60);
Now, I assume that the second Integer added to the Map, will return an int value
of 60.
If so, what happens to the sort at that point?
-nat

The assumption is incorrect. b now points to a new object, but the TreeMap
still points to the object originally used to created the Map entry.
Remember, a *copy* of the reference contained by b was passed to the
tm.put() method (pass by value). The reference contained in b cannnot be
changed by the called method and the reference used by the called method
cannot be changed by altering b. And, since Integer is immutable, you cannot
alter the object that both these references reference either. The sort order
is maintained.

- Virgil
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top