I would create a Set exactly HashSet to contains only char.for example a,b,c,d,e,f,g...
but these chars are not represented by the primitive type but I have an object
public FirstChar{
private char c;
public FirstChar(char c){
this.c = c;
}
}
Now i want to add the object FirstChar into a set but to avoid repeated elements I have to implement HashCode() and equals()
I know how to implement equals but how can i implement hashcode in the way I could have only one element in the set?
NB. Please don't say me to use Eclipse
EDIT: I've just read your comment that you only want one letter in the entire set - which sounds like a very odd requirement, but it's basically fulfilled by something like:
public final class FirstChar {
private final char c;
public FirstChar(char c) {
this.c = c;
}
#Override public int hashCode() {
return 0;
}
#Override public boolean equals(Object other) {
return other instanceof FirstChar;
}
}
In other words, every instance of FirstChar is deemed equal to every other instance, and they all have the same hash code. As I say, this is really strange... is it definitely what you want?
Original answer
Implementing hashCode() for a value which only logically has a single character is easy:
#Override
public int hashCode() {
return c; // Use implicit conversion to int
}
Check against the contract of Object.hashCode and you'll find this works fine - assuming your equals method basically just compares values of c. (It's not clear what you meant when you wrote "in the way I could have only one element in the set" - I assume you mean only one element per distinct character.)
However, I'm confused as to what value your FirstChar class provides over just using java.lang.Character. Is there any reason you can't just use a Set<Character>?
In any case, from what I can tell, the hashCode method in the Character class simply returns the char as an int.
In your specific case, if you want the set to only contain the first FirstChar added to it, you can make all FirstChars equal to each other:
class FirstChar{
private char c;
public FirstChar(char c){
this.c=c;
}
public String toString(){
return String.valueOf(c);
}
public boolean equals(Object o){
return o instanceof FirstChar;
}
public int hashCode(){
return 42;
}
}
But unless you have a very good reason, this doesn't sound like a good idea.
Related
Hi i'm just beginner learning about abstract classes & interfaces.
Everything we build our prof is testing by creating clones and comparing objects.
I've learned overriding the equals() method the detailed way…
#Override
public boolean equals(Object obj){
if (this == obj){
return true;
}
else if (obj == null){
return false;
}
...
else {
Obj x = (*Superclass*)obj;
…
}
I was now wondering if I could replace this long way by a short Version where I change the toString method, do a hashCode of the toString method and compare the hashCodes of my Objects (original & clone).
Would this be ok to do or is there any reason i shouldn't do it?
Would I be able to inherit the toString, hashCode and equals method and just adjust the clone() in subclasses if we assume that the subclasses use the same variables?
My idea was following
public abstract *Superclass*{
public String name; //would be private in org. code
public int hp; //would be private in org. code
public Superclass(){
}
#Override
public Superclass clone(){
return this; //(not sure if this is ok to use)
}
#Override
public String toString(){
Class temp = getClass();
return temp.getName() + this.name + " " + this.hp;
}
#Override
public int hashCode(){
int hcModify = 10;
int hcCurrent = this.toString().hashCode();
return hcModify * hcCurrent;
}
#Override
public boolean equals(Object obj){
return this.hashCode() == obj.hashCode())
}
}
So the first thing to note is that your equals method will throw an error if obj is null - you can't use any . operators on null.
Your clone method is dangerous if there's mutability in play - mutability means "values can be changed". Because it just returns a reference, changes will be reflected in both the original and "cloned" values (because they're the same.) This is not what most developers would expect. (I suggest looking up deep vs. shallow clones, which is related.)
x = new Thing()
y = thing.clone()
x.changeInSomeWay()
//is y now also changed?
The method of using hash codes for equality is not necessarily good or bad - it depends on the relation of the object to its hash and toString functions, and if there are colisions. Some objects will have hash or toString colisions, where different objects will have the same hash or string representations - particularly large or complex objects, where those representations don't include all of the data that you'd want to be reflected in an equality check.
Yours is actually an example of this. You're using an int hashcode, which only has 2^32 (or whatever) possible values, while Strings have, in principle, infinite possible values; by the pigeonhole principal, there must therefor be multiple objects with different names but the same hashcode.
In general, it's not a safe practice, and can lead to weird, difficult to diagnose errors.
I'm not sure why you're multiplying by 10?
Let me give you an example for what i'm trying to achieve. Look only to the numbers because it's a card game.
I have:
harten5 klaveren4 klaveren7 schoppen5 ruiten5 schoppen2 klaverenheer schoppenheer schoppendame schoppen6 klaverenboer schoppen8 ruitenheer klaveren6...
I want to sort this on the value to:
schoppen2 harten2 ruiten2 klaveren2 ruiten3 harten3 schoppen3 klaveren3 klaveren4 harten4 schoppen4 ruiten4 harten5 schoppen5 ruiten5...
But i get the 10 before the 2 like this:
schoppen10 ruiten10 harten10 klaveren10 schoppen2 harten2 ruiten2 klaveren2 ruiten3 harten3 schoppen3 klaveren3...
This is my basic compareTo Method:
#Override
public int compareTo(Card p) {
return this.value.compareTo(p.value);
}
Because String's (I guess this.value is String) compareTo compares lexicographically, whilst you want numerically. So you have to reimplement it, take substring (or find the last part which is a digit, convert it to Integer and then user compareTo on that Integer.
In general, I think your class Card could be improved a bit. In particular, I would rewrite it:
class Card {
private String value;
private Integer rank;
...
public int compareTo(Card c) {
// Additional logic if you need to consider
// also value (suite) in comparison
return this.rank.compareTo(c.rank);
}
}
But you can also use an enum for this purpose.
String java API compareTo
I'm guessing you want the reverse order? If so, then just change your implementation to this:
#Override
public int compareTo(Card p) {
return p.value.compareTo(this.value);
}
It really depends on what the type of "value" is and how the "compareTo" is implemented. Alternatively, you could just do this if "value" is an integer:
#Override
public int compareTo(Card p) {
return this.value - p.value;
}
I believe your value is stored as an String. If you do not want to change the data type of value, you can implement the compareTo method in the following way:
public int compareTo(Card p) {
return Integer.parseInt(this.value).compareTo(Integer.parseInt(p.value));
}
I've implemented the Apriori algorithm. it works pretty well, but I ran into a strange problem: I've defined a Rule class to maintain the generated rules.
Here it is:
public class Rule
{
private Set<Integer> left;
private Set<Integer> right;
private LookupArtist lookupArtist;
public Rule(LookupArtist lookupArtist){
left = new HashSet<>();
right = new HashSet<>();
this.lookupArtist = lookupArtist;
}
#Override
public boolean equals(Object another){
Rule rule = (Rule) another;
if(this.left.equals(rule.getLeft()) && this.right.equals(rule.getRight()))
return true;
else
return false;
}
#Override
public String toString(){
/* print the object */
}
public void addToLeft(Integer toAdd){
left.add(toAdd);
}
public void addToRight(Integer toAdd){
right.add(toAdd);
}
public Set<Integer> getLeft(){
return left;
}
public Set<Integer> getRight(){
return right;
}
}
I also implemented the equals() method in a different way just to try:
#Override
public boolean equals(Object another){
Rule rule = (Rule) another;
boolean flag = true;
for(Integer artist : left){
if(flag)
if(!rule.left.contains(artist))
flag=false;
}
if(flag)
for(Integer artist : right){
if(flag)
if(!rule.right.contains(artist))
flag=false;
}
return flag;
}
The LookupArtist object is used to map the integers to some Strings.
The problem is that when I print out the rules I found that some rules appear two times. I also found in debug mode some replicated rules, so it isn't be a print problem. The rules are saved in a map like this:
static Map<Rule, Float> rules;
.
.
.
Rule rule = new Rule(lookupArtist);
for(int j=0;j<i;j++){
rule.addToLeft(a[j]);
}
for(int j=i;j<a.length;j++){
rule.addToRight(a[j]);
}
if(!rules.containsKey(rule)){
rules.put(rule, getRuleConfidence(rule));
}
Any idea where the problem can be?
When using a HashSet for storing objects of a class that has a custom equals implementation, you must have a matching custom implementation for hashCode.
If two objects are equal (according to the custom equals implementation), they must have the samehashCode. In the code you posted, I don't see an overriding ofhashCodein theRule` class.
When you add an instance to the HashSet, hashCode method is used to determine the index in the hash table in which the instance will be stored. Then, the linked list of instances stored in this index is iterated to see if the instance is already there. When iterating over that list, equals is used. If two objects that are equal are mapped by hashCode to different indices in the HashSet, the duplication won't be detected, since they would be stored in separate linked lists.
This is stated in the Javadoc of equals :
* Note that it is generally necessary to override the <tt>hashCode</tt>
* method whenever this method is overridden, so as to maintain the
* general contract for the <tt>hashCode</tt> method, which states
* that equal objects must have equal hash codes.
And in the Javadoc of hashCode :
* <li>If two objects are equal according to the <tt>equals(Object)</tt>
* method, then calling the <code>hashCode</code> method on each of
* the two objects must produce the same integer result.
You should always override hashCode when you override equals and vice versa.
Add something like this to your Rule class:
#Override
public int hashCode() {
return left.hashCode()
^ right.hashCode()
^ lookupArtist.hashCode();
}
Here is a good answer explaining why it's important to override both.
Also, your equals method can be written as
#Override
public boolean equals(Object another){
Rule rule = (Rule) another;
return left.equals(rule.left)
&& right.equals(rule.right)
&& lookupArtist.equals(rule.lookupArtist);
}
A final remark: Your other attempt at the equals-implementation is not symmetrical, i.e. it's not the case that rule1.equals(rule2) if and only if rule2.equals(rule1). That's a violation of the contract of equals.
And where is your hashCode() method? It is also very important :)
I am trying to write a custom hashCode fn, but I am not able to figure out the correct way to do that.
public class Person {
String name;
List<String> attributes;
#Override
public boolean equals(Object o) {
// Persons are equal if name is equal & if >= 2 of attributes are equal
// This I have implemented
}
#Override
public int hashCode() {
final int PRIME = 59;
int result = 1;
result = (result*PRIME) + (this.name == null ? 0 : this.name.hashCode());
//Not sure what to do here to account for attributes
return result;
}
}
I want the hashCode fn to be such that:
"If object1 and object2 are equal according to their equals() method, they must also have the same hash code"
Not sure how to do that?
As Oli points out in the comments, you cannot solve this by implementing equals() and relying on a Set to de-duplicate for you. Weird things could happen.
Thus you must resort to coding this yourself. Add the first item from your list into your new de-duplicated list. Then for each remaining item in your original list, compare it with those already present in your de-duplicated list and only add it if it passes your non-duplicate test.
Easiest way to fulfill the contract of the equals/hashcCode methods is to return a constant:
#Override
public int hashCode() {return 13;}
Otherwise your solution with a hash code based only on name will work.
I want to pass in an arraylist and sort it no matter whats in it
Error I am getting: Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Character
ArrayList myArray = new ArrayList();
myArray.add("wayne");
myArray.add("bob");
myArray.add('h');
myArray.add(4);
myArray.add(5.50);
ArrayList sortedArray = Validate.Sort(myArray);
for(Object x: sortedArray)
{
System.out.println(x);
}
public static ArrayList Sort(ArrayList value)
{
Collections.sort(value);
return value;
}
Your ArrayList has a mix of String and char values. So when the two try to get compared, the String's compareTo method is being called. It has a signature of compareTo(String,String), so it's trying to cast the char to a String. Either put all Strings in, or write a custom comparator that handles mixed types like this.
Take a look at Comparator:
http://docs.oracle.com/javase/6/docs/api/java/util/Comparator.html
In your case the compareTo() may look like:
public int compareTo(Object a, Object b){
if(a == b)
return 0;
if(a==null)
return 1;
if(b==null)
return -1;
return a.toString().compareTo(b.toString);
}
But I think this would be kind of useless.
I want to pass in an arraylist and sort it no matter whats in it
What is this supposed to mean? A total ordering is a binary relation which satisfies some properties (antisimmetry, transitivity, totality). More easily, given two elements, you must identify a criterion to determine which is smaller/bigger than the other.
You cannot do this, unless you know what these elements actually are. If you want to sort an array of whatever, given object A and B, whose types you don't even know, how can you tell which is bigger than the other?
In Java, you might use the hashCode, which is indeed a criterion, but it's hardly useful. If you want to avoid duplicates, you can use a Set rather than a List. Anyway, if you really want to sort elements based on their hashCode, you can do it like this:
private static final Comparator<Object> hashComparator
= new Comparator<Object>() {
#Override
public int compare(Object a, Object b) {
return System.identityHashCode(a) - System.identityHashCode(b);
}
#Override
public boolean equals(Object obj) {
//this is a static singleton, nothing can be equal to it
return false;
}
};
public static ArrayList Sort(ArrayList value)
{
Collections.sort(value, hashComparator);
return value;
}
EDIT: if you are interested in sorting a list of just Strings and Characters (or if you want to sort items based on their string representation) the right thing to do is probably convert everything to strings, or use a SortedMap<String, Object>. Otherwise, you can do the same I just showed you before, but using a more specific compare function, such as:
public int compare(Object a, Object b) {
return a.toString().compareTo(b.toString());
}