Java clone() inquiry - java

Having written the code below, I was wondering why clone() doesn't return the same hashcode for each additional instance. Am I doing something wrong?
public class Accessor implements Cloneable {
public static void main(String[] args) {
Accessor one = new Accessor();
Accessor two = one.clone();
System.out.println("one hahcod " + one.hashCode()
+"\ntwo hashcode " + two.hashCode());
}
public Accessor clone(){
try{
return (Accessor)super.clone();
}
catch (CloneNotSupportedException err){
throw new Error("Error!!!");
}
}
}

Since Accessor does not override hashCode, you will get the default implementation of Object.hashCode. This has implementation-defined semantics but will basically cast the address of the object to an integer, such that distinct object instances will have different hashCodes.
See What is the default implementation of `hashCode`? for more information on the above.
Note that if you are going to implement hashCode, you should also implement equals. For a good reference on equals and hashCode, read Joshua Bloch's Effective Java (or see Best implementation for hashCode method)

Because it is a different object. You are invoking the cloning inherited from Object in this case. For each new object you will have a different dashcode. If you open the source code of Object in java what you will find there is the following:
public native int hashCode();
public boolean More ...equals(Object obj) {
return (this == obj);
}
The key point here is that once you clone an object A clone of B A==B will always return false.
Then if you read the hashcode documentation it states the following :
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. It is not required that if two objects are unequal
according to the equals(java.lang.Object) method, then calling the
hashCode method on each of the two objects must produce distinct
integer results. However, the programmer should be aware that
producing distinct integer results for unequal objects may improve the
performance of hashtables.

The clone method creates a shallow copy of your first object but your Accessor class has no instance field and does not override hashCode method, as a consequence the instances of this class get the default behaviour from Object class for hashCode. This behaviour is similar as calling System#identityHashCode with your object as parameter.

Related

How to use an object that was called from a method in Java?

I'm trying to figure out what the syntax is for calling an object inside a method..
Pseudocode:
boolean check(Object someObject) {
return someObject == theOtherObject;
}
public static void main(String args[]) {
someClass one = new someClass();
someClass two = new someClass();
one.check(two);
}
So the check method is supposed to check whether the two objects are equal, but how would I specify the other object (theOtherObject should be one)?
Thanks in advance!
One word answer: this
boolean check(Object someObject) {
return someObject == this;
}
which will test object identity only. You should override equals and use that.
if (one.equals(two)) {
// ...
}
You can have the boolean check(Object o) method inside SomeClass and check
boolean check(Object o) {
this == (SomeClass) o;
}
This would work only if both reference variables are pointing to same object. Moreover the right way to check if two objects are meaningfully equal would be to use the inherited equals and hashCode method.
Override equals and hashCode method.
Why do I need to override the equals and hashCode methods in Java?
https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#equals-java.lang.Object-
So what you're asking for there is actually already a command in java.lang.Objects class to compare to objects.
one.equals(two)
the comparison this does is called a shallow comparison. So if that's what you're looking to do then this would work. For reference, the definitions of shallow comparison defined by geeksforgeeks.org is
Shallow comparison: The default implementation of equals method is defined in Java.lang.Object class which simply checks if two Object references (say x and y) refer to the same Object. i.e. It checks if x == y. Since Object class has no data members that define its state, it is also known as a shallow comparison.
if you're looking to do a more complicated comparison you're the best bet would be to actually override the equals command in the one class file
this article would be a good place to start to learn more about this topic.
https://www.geeksforgeeks.org/equals-hashcode-methods-java/

Adding Object to HashSet

I am trying to add an Object (Exception) to a Set, however it adds every Exception, eventhough some are duplicates.
debug
In my case duplicates are Exceptions which have the same Detail message.
How do I properly add the Exceptions to the HashSet only if the Exception.getDetails() doesn't already exist?
Is there another approach than a HashSet?
Performance is a criteria here, quadratic solutions (O(n^2))are not an option.
You have a few options:
override hashcode and equals in your exception class
use a TreeSet with a custom Comparator
use a Map<String, Exception> where the key is the getDetails() result (for example, a HashMap)
You need to override how the Execptions are compared so it recognises duplicates the way you want. You can't do this for a HashSet but you can for TreeSet e.g.
Set<Exception> exceptions = new TreeSet<>(Comparator.comparing(Object::toString));
This example compares the toString which is the exception type and message in most cases.
If you really want to use a HashSet you need to wrap the Exception in a class which implements hashCode and equals the way you want.
If all you care about is the type and message you can store just the toString of each exception
final Set<String> exceptions = new HashSet<>();
public void addException(Exception e) {
exceptions.add(e.toString());
}
You need to redefine equals and hashCode methods.
If the detail is a String you can redefine them as follow
public boolean equals(Object obj) {
if (!(obj instanceof YourException)) {
return false;
}
return getDetail().equals(((YourException) obj).getDetail());
}
public int hashCode() {
return getDetail().hashCode();
}
Consider this code as a base to program. You have to check for null values for example.
Once redefined equals and hashCode inserting YourException in a TreeSet is an operation done in O(log(n)) where n is the size of the set, from javadoc:
This implementation provides guaranteed log(n) time cost for the basic operations (add, remove and contains).

Why does object.equals(new Integer(1)) equate to true?

I am struggling to understand this Koan:
#Koan
public void equalsMethodCanBeChangedBySubclassesToTestsIfTwoObjectsAreEqual() {
Object object = new Integer(1);
assertEquals(object.equals(object), true);
assertEquals(object.equals(new Integer(1)), __);
// Note: This means that for the class 'Object' there is no difference between 'equal' and 'same'
// but for the class 'Integer' there is difference - see below
}
As far as I understand, because object is an instance of the Object class, the .equals() method has not been overwritten, and therefore checks for object equality.
If new Integer(1) creates a new instance, then it should be a separate object to object. Following my train of thought, the correct answer should be false, but only true makes this pass. Where is the flaw in my logic?
Edit: I understand that integers between -128 and 127 are cached. If my understanding of the object object is correct (as stated above), then this is irrelevant.
Integer overrides equals and checks if the underlying int is equal to the int of the other Integer instance, and if so, returns true. The reason why Integer's equals method is invoked, and not the one from Object, is that the runtime type of object is Integer.
Integer is an Object, but due to the overridden equals, no object identity is used.
All following boolean expressions evaluate to true:
print((new Integer(1).equals(1)));
print((new Integer(1).equals(new Integer(1))));
print((((Integer) 1).equals(new Integer(1))));
print(((Integer) 1).equals(1));
Now consider autoboxing, which reuses instances for values in the range [-128,127]. The following statements about object equality are all evaluating to true:
1 == ((Integer) 1)
((Integer) (-128)) == ((Integer) (-128)) // in autoboxing range
((Integer) (+127)) == ((Integer) (+127)) // same
((Integer) (-200)) != ((Integer) (-200)) // not autoboxing
((Integer) (+200)) != ((Integer) (+200)) // same
((Integer) (-128)) != (new Integer(-128)) // explicit new instance, so no autoboxing
((Integer) (+127)) != (new Integer(+127)) // same
As far as I understand, because object is an instance of the Object class, the .equals() method has not been overwritten, and therefore checks for object equality.
You've got this one completely wrong. Even though the static type of variable object is Object, it remains an instance of Integer. That is why equals() is directed to Integer's override, producing the right result.
Assigning an instance to a variable of base type, or an interface implemented by the class, does not "strip" the object of its subclass behavior. In particular, an instance of Integer retains all its behaviors as implemented in the Integer class, even though you have assigned the instance to a variable of type Object.
You are calling equals on an Integer object instance. It is dispatched at run-time to the implementation in the Integer class (which regards the Integer equal to any other Integer of the same numeric value). The compile-time type (the static type of the variable involved) does not (directly) matter.
If that was not the case, how would something like this work (where the interfaces involved have no implementations at all):
Comparable<Integer> a = 1;
Serializable b = 1;
assertTrue(a.equals(b));
Note that static methods are "dispatched" at compile-time. That's why you should call them using the class name, not an object instance (which is ignored, can even be null, and the compiler issues a warning).
Heard of Dynamic Method Dispatch?
When you use a super class reference to refer to subclass object, and if subclass has overridden method, this overridden method will be called.
Hence, though you are using Object object = new Integer(1);, calling equals on object will always call Integer.equals().
And Integer.equals() checks for integers' equality, not necessarily same same reference.
If new Integer(1) creates a new instance, then it should be a separate object to object.
That's where you are going wrong. A new instance of Integer(1) will be false for == but true for equals.

what is the difference between equals and contains methods

I was working with the TreeSet collection with the following code:
import java.util.*;
public class Employee implements Comparable<Employee>{
private int ID;
public Employee(int iD) {
ID = iD;
}
#Override
public int compareTo(Employee obj) {
return this.ID-obj.ID;
}
private static void intoTreeSet() {
Employee e1=new Employee(4);
Employee e2=new Employee(2);
Employee e3=new Employee(1);
Employee e4=new Employee(5);
Employee e5=new Employee(3);
Employee eTemp=new Employee(3);
Set<Employee> set=new TreeSet();
set.add(e1);set.add(e2);set.add(e3);set.add(e4);set.add(e5);
System.out.println("output says: ");
for(Employee e:set){
System.out.print(e.ID+" ~ ");
}
System.out.println();
if(set.contains(eTemp)){
System.out.println("C O N T A I N S !!!");
}
if(e5.equals(eTemp)){
System.out.println("E Q U A L S !!!");
}
}
public static void main(String[] args) {
intoTreeSet();
}
}
Output
output says:
1 ~ 2 ~ 3 ~ 4 ~ 5 ~
C O N T A I N S !!!
I am confused to see the output. I want to know, if it does NOT pass equals case, then how come it pass contains case.
I know that two objects can only be equal if their class overrides equals method and they are equal according to some property. I intentionally did not override equals method to see how contains work. If it were a non-tree based collection lets say an ArrayList it would NOT have passed contains test. Why is it so ? can any one explain this behaviour and clear my confusion.
The javadoc for java.util.TreeSet says:
Note that the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equals if it is to correctly implement the Set interface. (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Set interface is defined in terms of the equals operation, but a TreeSet instance performs all element comparisons using its compareTo (or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the set, equal. The behavior of a set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Set interface.
In other words, the implementations of compareTo and equals must be consistent with each other. If they're not, the behaviour of TreeSet will be erratic. It may work, it may not. To understand when it does and when it doesn't you need to look closely at the TreeSet implementation, but since the javadoc is very explicit on the conditions under which TreeSet works, it's really not a good idea to try and subvert it.
The most important point to remember here is, a TreeSet is a SortedSet which performs element comparisons using compareTo (or compare) method.
The Employee class is comparable. From the definition from the docs of the comparable interface,
This interface imposes a total ordering on the objects of each class
that implements it. This ordering is referred to as the class's
natural ordering, and the class's compareTo method is referred to as
its natural comparison method.
So if your compareTo method returns 0, for two instances of the same class, they are considered to be naturally equal by the TreeSet.
The document also says,
It is strongly recommended (though not required) that natural orderings be consistent with
equals. This is so because sorted sets (and sorted maps) without explicit
comparators behave "strangely" when they are used with elements (or
keys) whose natural ordering is inconsistent with equals.
Though it is not defined how "strangely" it can behave.
In our case e5.equals(eTemp) is false, since the equals method is not overridden.
And e5.compareTo(eTemp) is true, so from the set's perspective e5 and eTemp are equal.
To demonstrate this you can perform the below operations:
Employee e1 = new Employee(3);
Employee e2 = new Employee(3);
set.add(e1); // gets added to the set
The below operation will return false because the set considers an equivalent of e2 already to be present in the set, though e1.equals(e2) is false, and the size of the set remains same.
System.out.println(set.add(e2)); // false
So to to be consistent, you could override the equals method, though it is not necessary.

Implementing bidirectional relations between objects of the same class

I have to implement a class whose instances have a bidirectional relation to each other. For example I have the class FooBar which should offer the method sameAs(FooBar x) and maintain a Set for each instances containing its equivalent instances. So if I call foo.sameAs(bar), the Set in foo should contain bar and vice versa. Invoking bar.sameAs(foo) doesn't work, of course.
For clarifiction: the instances of this class are only semantically equal. equals should still return false.
The solutions I've come up with is either to implement a private method internalSameAs(FooBar x) which is invoked from sameAs(FooBar x) or to use a static method sameAs(FooBar x, FooBar y).
Solution 1:
class FooBar {
Set<FooBar> sameAs = new HashSet<FooBar>();
public void sameAs(FooBar x) {
this.internalSameAs(x);
x.internalSameAs(this);
}
public void internalSameAs(FooBar x) {
sameAs.add(x);
}
}
Solution 2:
class FooBar {
Set<FooBar> sameAs = new HashSet<FooBar>();
public static void sameAs(FooBar x, FooBar y) {
x.sameAs.add(y);
y.sameAs.add(x);
}
}
Which one would you prefer and why? Or is there another way I didn't think about?
The naming you've used is confusing. sameAs sounds as though it's a test which should return a boolean, but from your code it seems it would be more appropriately named declareSameAs. When you call foo.sameAs(bar), you're declaring that foo and bar are the same, not doing a test, correct?
The problem is that with your code you can declare
x.sameAs(y);
y.sameAs(z);
but it won't be the case that x is the same as z, which is presumably not what you want (and if it is what you want, you definitely need to change the method name).
It seems to me you want to divide your instances into sets, and have each instance keep a reference to the set it's in (not to a separate set internal to the instance). When you make a new declaration that two instances are the same, you need to combine the sets, and ensure all affected instances have a reference to the combined set.
are you flexible with the data structures to be used? If so you could use a Multimap (from Guava Collections) that is static amongst all the instances of the class FooBar. In that Multimap you can have the keys as FooBar references (or a unique id if you have one) and the values would be the references (or id.s) of the FooBars that have the sameAs relation.
Maybe there's a different way: sameAs sounds pretty similiar to equals. If we do not need equals for something else, then I'd simply implement the equals method on FooBar so that we simply do a
if (foo.equals(bar))
System.out.println("We're equal (aka: 'equivalent/the same')");
In this case, we do not need any set - just a rule to determine, if two instances are equal.
You could store the sameness information in a separate datastructure outside of those classes. A central map could do the job:
HashMap<FooBar, Set<FooBar>> sameFooBars;
If you have "same" objects, simply add them to the map:
public static void addSameObjects(FooBar foo1, FooBar foo2) {
Set<FooBar> set = getMap().get(foo1);
if (set == null) {
set = new HashSet<FooBar>();
getMap().put(foo1, set);
}
set.add(foo2);
// serious implementation avoid code duplication...
set = getMap().get(foo2);
if (set == null) {
set = new HashSet<FooBar>();
getMap().put(foo2, set);
}
set.add(foo1);
}
And the test:
public static boolean isSame(FooBar foo1, FooBar foo2) {
if (getMap().get(foo1) == null)
return false;
return getMap().get(foo1).contains(foo2);
}
Do you really need to maintain a list of equivalences in ALL objects? If possible I would separate the set of equivalences from the objects themselves. This will be easier to maintain.
Then you can use the multimap of #posdef or more simply a Map> to stay with standard JAVA API.
Your "bidirectional" samesAs(...) method sounds like Object.equals(...), which, according to javadoc is a "an equivalence relation on non-null object references". If this is what you want, then you just have to override equals in your class.
I'm a bit lost when you say that "FooBar shouldmaintain a Set for each instances containing its equivalent instances". If you want to build equivalent classes for FooBar objects, then I think it's a good idea to use a java Collection to represent them, and more precisely a Set.
Here is a quickly hacked example:
public class FooBar {
#Override
public boolean equals(Object other) {
// do whatever fancy computation to determine if
// the object other is equal to this object
}
}
and for the equivalent class:
#SuppressWarnings("serial")
public class FooBarEquivalentClass extends HashSet<FooBar> {
#Override
public boolean add(FooBar e) {
if (isEmpty())
return super.add(e);
else if (e.equals(iterator().next()))
return super.add(e);
else
return false;
}
}
"same as" but not "equal to" sounds like you should be using Comparable.
I think it makes more sense to implement compareTo() or sameAs() as an instance method rather than a static since you will always need two real instances to do any comparison.
Sounds like what you want are to separate the equivalence groups from the object instances.
Make a Map<FooBar, Set<FooBar>> and note that when you lookup an object the set will include itself.

Categories

Resources