I'm getting ClassCastException even though I overriden compareTo() [closed] - java

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I am getting ClassCastException error. This error occurs when I insert the object that is derived from a class I have created.
My code is below:
When I run, I always get ClassCastException error.
Also, the comparator of my class is shown as null in debugger.
I have written a comparator (as far as I know) and overridden necessary methods.
How can I use a Set<> with a class that I have created and use contains() method?
public class Person implements Comparable<Person>
{
int age;
double height;
public Person(int age, double height)
{
this.age = age;
this.height = height;
}
#Override
public int compareTo(Person person)
{
return age - person.age;
}
public boolean equals(Object obj)
{
final Person other = (Person) obj;
if (this.age == other.age)
return true;
return false;
}
public static void main(String[] args)
{
Set<Person> people = new HashSet<>();
Person p1 = new Person(10, 1.00);
Person p2 = new Person(11, 1.10);
Person p3 = new Person(12, 1.20);
Person p4 = new Person(14, 1.40);
people.add(p1);
people.add(p2);
people.add(p3);
people.add(p4);
if(people.contains(12))
System.out.println("contains");
else
System.out.println("does not contain");
}
}
I have managed to get rid of the error. But now, the output is "does not contain".

What I am about to suggest has nothing to do with ClassCastException, which is thrown simply because you are checking contains with an int argument on a set of objects of type Person ... short answer: you can't cast an object to a subclass of which it is not an instance. Even the javadoc says exactly that.
For situations like this, I really like to use Guava predicates. A predicate allows you to apply a boolean condition to any iterable, returning those elements that satisfy the specified condition. In your example, you can define predicates that return the subset of people of whatever age you want.
Predicate<Person> getAgePredicate(final int age) {
return new Predicate<Person>() {
public boolean apply(Person p) { return p.age == age; }
};
}
Set<Person> people = new Hashset<>();
... // populate people
Set<Person> peopleOfAgeTwelve = Sets.filter(people, getAgePredicate(12));
Hope this helps.

I assume that your class Adjacent implements Comparable interface based on your code. And your class contains a method called getID(). So therefore when you override the compareTo() method, you want to make sure that the object comparison makes sense. I'm not sure what your getID() returns. But it seems like integer. So you might want to change the implementation of compareTo() as follows:
#Override
public int compareTo(Adjacent adj) {
return this.getId() - adj.getId();
}
So this way the comparison will return negative/zero/positive depending on the ID comparison of two Adjacent class objects.
Also in your overrided equals() method, the implementation is incorrect because two objects are not necessarily equal even if they have the same hash code. A good example of overriding equals and hashCode methods is given in another SO post. Also, in your case, I think you probably don't even need to override equals method since your class implements Comparable interface already.

Don't call contains with a parameter that's a different type; this behavior is actually documented. The contains() method is a non-generic method for legacy reasons, and it's not safe if you're using a TreeSet. If you implement hashCode() and equals() and switch to a HashSet, your problems will go away.
Do you really need people sorted by age?
Edit: I see what you're trying to do, now. You don't want a Set, you want Map<Integer, Collection<Person>>, or just a single pass loop to look for the given age.
for (Person p : people) {
if (p.age == 12) ...;
}
or
Map<Integer, Set<Person> peopleByAge = new HashMap<Integer, Set<Person>>();
for (Person p : people) {
if (!peopleByAge.contains(p.age)) {
peopleByAge.put(p.age, new TreeSet<Person>();
}
peopleByAge.get(p.age).add(p);
}
if (people.age.containsKey(12)) ...

Related

java-project -Comparable Interface [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I'm trying to create a method in java which compares some products. I need to compare them by unit of measure and then by quantity, but I don't know how. I need to use object.equals ?
I'll put my code here.
public abstract class Produs implements Comparable {
private String tipProdus;
private String unitateMasura;
private int cantitate;
public Produs(String tipProdus, String unitateMasura, int cantitate) {
super();
this.tipProdus = tipProdus;
this.unitateMasura = unitateMasura;
this.cantitate = cantitate;
}
public Object genereazaDescriere() {
Object String = null;
return String;
}
public void compareTo() {
tipProdus.equals(unitateMasura);{
}
}
}
First of all, you can not create objects from an abstract class so you need to change that or just forget about that constructor because you won't be able to use it.
To compare two objects you need to create a comparator class so you would be able to compare objects according to the attributte you want to.
So in this case you need to create two comparators, one to compare them by unit of measure and another to compare it by quantity.
So it would be something like this:
Comparator by unit of measure:
public class UnitOfMeasureProdusComparator implements Comparator<Produs> {
#Override
public int compare(Produs p1, Produs p2) {
return p1.getUnitateMasura().compareTo(p2.getUnitateMasura());
}
Comparator by quantity:
public class QuantityProdusComparator implements Comparator<Produs> {
#Override
public int compare(Produs p1, Produs p2) {
return p1.getCantitate().compareTo(p2.getCantitate());
}
So now for example if you have an arraylist of Produs objects you can compare them like this:
ArrayList<Produs> products = new ArrayList<>();
Produs p1 = new Produs("x", "centimeters", 5);
Produs p2 = new Produs("y", "meters", 4);
products.add(p1,p2);
//now you have two objects created so if you want to sort them by there quantity u can do it like this:
Collections.sort(productos, new QuantityProdusComparator());
It will sort the list according to the comparator you use.
Internally the comparator class will send a 0 if the objects are equal, a -1 if the object is smaller than or a 1 if the object is bigger than.
If you comparing string attributes it will do it in alphabetical order.

What is the cause of this odd behaviour from Hashset in Java? [duplicate]

This question already has answers here:
Java Hashset.contains() produces mysterious result
(3 answers)
HashSet allows duplicates
(6 answers)
HashSet adds duplicate entries despite implementing both hashCode() and equals()
(2 answers)
Closed 3 years ago.
I was messing around trying to understand how HashSets behave and I've run into this problem that I can't get my head around. The 2nd and 3rd dog objects have the same name, and equals() and hashcode() have been overriden to make names mean equality. Despite this, the hashSet still has duplicates, and I can't figure out why.
I reread the data structures chapter of Head First Java but it still suggests that my code should work in theory.
public class DataStructsTests<E> {
HashSet<Dogs> tree = new HashSet<Dogs>();
HashSet<Dogs> treeOwner = new HashSet<Dogs>();
public static void main(String[] args) {
DataStructsTests<String> d = new DataStructsTests<String>();
d.go();
}
public void go() {
Dogs dog = new Dogs("Scout", "a");
tree.add(dog);
treeOwner.add(dog);
Dogs dog2 = new Dogs("Brodie", "b");
tree.add(dog2);
treeOwner.add(dog2);
Dogs dog3 = new Dogs("Brodie", "c");
tree.add(dog3);
treeOwner.add(dog3);
System.out.println(tree);
System.out.println(treeOwner);
System.out.println(dog2.equals(dog3));
System.out.println(dog2.hashCode() + " " + dog3.hashCode());
}
class Dogs {
private String name;
private String ownerName;
public Dogs(String n, String o) {
name = n;
ownerName = o;
}
public boolean equals(Dogs d) {
return name.equals(d.getName());
}
public int hashCode() {
return name.hashCode();
}
public String getName() {
return name;
}
public String toString() {
return name;
}
Running the program returns this:
[Brodie, Brodie, Scout]
[Brodie, Brodie, Scout]
true
1998211617 1998211617
Even though equals() returns true and the hashcodes are the same, the duplicates still remain.
Edit: Turns out the problem was that I hadn't overridden the equals() method properly as I used Dog rather than Object.
equals takes an object of type Object, which is the one being called by HashSet. You need something like:
#Override
public boolean equals(Object d) {
if (! d instanceof Dogs){
return false;
}
return name.equals(((Dogs) d).getName());
}
Here are the components of this answer:
public boolean equals(Object d) - equals, at least the version inherited from Object, is defined to take Objects, so to override it, you must also take an Object.
#Override - tells the compiler to warn you if you make a mistake like you made in your question.
d instanceof Dogs - checks if the Object fed in is even a Dogs in the first place.
((Dogs) d).getName() - The reason for the cast to Dogs is because d is now being passed in as an Object, so you won't automatically gain access to Dogs's methods unless you explicitly say that you want to view the Object as a Dogs.
And one final note: the general convention in Java is to name classes in the singular, unless there is some reason to believe that each instance will be multiple somethings. This is to avoid ambiguity. Dog d makes clear what d is; it is clearly a Dog. What, exactly, is a Dogs d? Is d many dogs, and they just don't have their own object type? It becomes a little ambiguous.

Java compareTo() method returns classCastException

Let's assume I have an Employee base class and Manager subclass which extends Employee.Now let's say I create an object x of type Employee and object y of type Manager and call x.compareTo(y) no exception is triggered and x and y is compared as Employees namely y is cast to an Employee but when I call y.compareTo(x) I get a classCastException.I need to know why this happens and how to prevent x.compareTo(y) to execute as x and y are from different classes.My idea is to use getclass() method in Reflection class like this:
if (getClass() != other.getClass())
throw new ClassCastException();
I also want to know is there any other way to implement this.
You should implement compareTo() in the class Employee and start it with:
Employee o = (Employee)other;
Then continue with comparing this to o - this will ensure you're comparing two Employees (which is the lowest common denominator).
Because your Manager is an Employee but Employee is not a Manager See below
http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html
instance of can be usefull in such cases
here Manager is a Employee.
but Employee is not Manager.
Quote from Effective Java, Item 12:
Let’s go over the provisions of the compareTo contract. The first provision says that if you reverse the direction of a comparison between two object refer- ences, the expected thing happens: if the first object is less than the second, then the second must be greater than the first; if the first object is equal to the second, then the second must be equal to the first; and if the first object is greater than the second, then the second must be less than the first. The second provision says that if one object is greater than a second, and the second is greater than a third, then the first must be greater than the third. The final provision says that all objects that compare as equal must yield the same results when compared to any other object.
One consequence of these three provisions is that the equality test imposed by acompareTo method must obey the same restrictions imposed by the equals con- tract: reflexivity, symmetry, and transitivity. Therefore the same caveat applies: there is no way to extend an instantiable class with a new value component while preserving the compareTo contract, unless you are willing to forgo the benefits of object-oriented abstraction (Item 8). The same workaround applies, too. If you want to add a value component to a class that implements Comparable, don’t extend it; write an unrelated class containing an instance of the first class. Then provide a “view” method that returns this instance. This frees you to implement whatever compareTo method you like on the second class, while allowing its cli- ent to view an instance of the second class as an instance of the first class when needed.
All Manager are Employee but not all Employee are Managers. Since all the attributes of Employee are available in Manager,Manager can be casted to Employee. But attributes of Manager is unavailable to Employee, so cast is not possible.
My suggestion is to override compareTo() method in your classes and cast the object Employee.
If your are using compareTo method then i am excepting you have implemented Comparable interface in your class and provide a implementation of the method compareTo. let me know how you are comparing object on what logic ,based on that only you get the solution.
I have little bit confuse on this
if (getClass() != other.getClass())
throw new ClassCastException();
if it is the code in your compareTo method then rather then doing this create one more interface say "XYZ" and implement that Interface to both the class
check the logic
public int compareTo(T obj){
if(this instanceof XYZ && obj instanceof XYZ)){
return 0;
}else{
throw new ClassCastException();
}
}
You could perhaps use isAssignableFrom which will return true or false and then use it for doing further comparison or equals etc. Not sure why you would need this in compareTo; however.
Anyways assuming name , salary for an employee and set of reportees for manager and then for example further just comparing salaries as part of compareTo.
public class Test{
public static void main(String[] args) {
class Employee implements Comparable<Employee> {
public Employee(String string, int salary) {
this.name = string;
this.salary = salary;
}
public Employee() {
name = "";
salary = 0;
}
String name;
Integer salary;
public int compareTo(Employee o) {
return o!=null && getClass().isAssignableFrom(Employee.class)
? salary.compareTo(o.salary) : Integer.MIN_VALUE;
}
}
class Manager extends Employee {
public Manager(String name, String[] subordinates) {
super(name, 1000000);
reportees = subordinates;
}
String[] reportees;
}
Employee e = new Employee("me", 1000);
Employee e1 = new Employee("mycolleague", 2000);
Manager m = new Manager("myboss", "me mycolleague".split(" "));
System.out.println(e1.compareTo(e));
System.out.println(e.compareTo(m));
System.out.println(m.compareTo(e)); // this gives INT.MIN as you cannot compare manager to employee
}
}

Can I define my own subclass of java.util.List?

Can I define my own list in Java?
I have my own list-type class that is very similar to a LinkedList, called PersonList.
In another program, I'm using a Comparator, so I need to have a List() object as the parameter.
Is it possible to make the following statement, if I make changes in my code?
List list1= new PersonList();
PersonList doesn't extend or import anything.
You'd need to implement the built in interface java.util.List. It would need to define all the methods listed in the interface java.util.List.
You just have to overload the equals function which is implemented by every
class of Type Object (Every class). The list implementation will use your equals implementation due to the polymorphic concept of OOP.
I strongly recommend to use the given List implemenmtations because they meet all
performance issues you don't even think about. When you have concurrency issues refer to the documentation.
In order to achieve customized comparison you have to implement the Comparable interface
and implement its method toCompare(..);
In this way you can use all given Collection API classes and extend them using your own
comparison or equals algorithm which meets your application needs.
Update to to Comments
class Person implements Compareable {
#override
public int compareTo(Person p) {
return p.age > this.age; //Or whatever
}
#Override
equals(Object person) {
if (person instanceof Person) {
Person p = (Person)person;
if (p.x == this.x &&
p.y == this.y &&
p.address.equals(this.address) {
...
return true;
}
}
return false;
}
}
And now just intialize you list.
List<Person> personList = new ArrayList<Person>();
or
List<Persin> personList = new Vector<Person>();
or
LinkedList<Person> personList = new Queue<Person>();
and and and.
Collections.sort(personList);
To answer the question in the comment, "How would I go about writing my own Comparator for a Linked List?":
public class PersonListComparator implements Comparator<LinkedList> {
#Override
public int compare(LinkedList list1, LinkedList list2) {
// something that returns a negative value if list1<list2, 0 if list1 and
// list2 are equal, a positive value if list1>list2.
}
}
See the javadoc for Comparator, especially the text at the top. This explains what could happen if the compare function could return 0 when list1.Equals(list2) is false. It's not necessarily a problem, depending on how you use it.
Note that I'm still assuming you want to compare entire lists (rather than just individual Persons). Based on later comments, it looks like you want to compare Person objects, but provide different ways to compare ("depending on the different parameter being compared"). You could define more than one class that implements Comparator<Person>. Or you could define a class that takes a parameter when you construct the object:
public enum ComparisonType { NAME, AGE, WEIGHT } // whatever
public class ComparePerson implements Comparator<Person> {
private ComparisonType type;
public ComparePerson(ComparisonType type) {
this.type = type;
}
#Override
public int compare(Person p1, Person p2) {
switch(type) {
case NAME:
// return comparison based on the names
case AGE:
// and so on
...
}
}
}
I haven't tested this, so I could have made a mistake, but you get the idea. Hope this helps, but it's still possible I've misunderstood what you're trying to do.

HashCode and Equals in Java [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I understand the basic concept of overriding hashcode and equals in a class , But can anyone give me an example (code) where the equals will fail only because hashcode was not overridden ?
Thanks in advance.
It's not that equals itself will fail - it's that anything that relies on the contract of hashCode and its relationship to equals could fail. Here's an example:
import java.util.*;
final class Person {
private final String name;
public Person(String name) {
// TODO: Nullity prohibition
this.name = name;
}
#Override
public boolean equals(Object other) {
if (other == null || other.getClass() != Person.class) {
return false;
}
return name.equals(((Person)other).name);
}
}
class Test {
public static void main(String[] args) throws Exception {
Person p1 = new Person("Jon");
Person p2 = new Person("Jon");
System.out.println(p1.equals(p2)); // true
Set<Person> people = new HashSet<Person>();
people.add(p1);
people.add(p2);
System.out.println(people.size()); // 2!
}
}
HashSet assumes that because p1.hashCode() isn't the same as p2.hashCode(), the two elements must be unequal, so can both be in the set. That wouldn't happen if hashCode() were appropriately overridden.
Likewise you could have (with the same Person class);
Map<Person, String> map = new HashMap<Person, String>();
map.put(p1, "foo");
System.out.println(map.get(p2)); // null
This would print out "foo" if the two objects returned equal hash codes, as they're meant to - but again, because they don't, the HashMap thinks there's no match.
Eric Lippert's blog post on GetHashCode is a good introduction to this - it's C#-based, but it applies equally to Java.
If your equals is failing it is because you implemented equals wrong.
Here is how to do it correctly:
the answer to What issues should be considered when overriding equals and hashCode in Java?.
but, just for fun here is an example of an equals method that will fail if hashcode is not overridden:
//NEVER DO THIS
#Override
public boolean equals(Object o){
ThisObject obj = (ThisObject)o;
return this.hashCode() == obj.hashCode();
}

Categories