Trouble implementing the comparable interface - java

I keep getting the error: Student is not abstract and does not override abstract method compareTo(java.lang.Object) in java.lang.Comparable
Why is this? What this is trying to accomplish is taking a list of students and comparing them by GPA.
public class Student implements Comparable
{
private String name;
private double gpa;
public Student(String name, double gpa)
{
this.name = name;
this.gpa = gpa;
}
public String getName()
{
return name;
}
public double getGpa()
{
return gpa;
}
public String toString()
{
return "Name: " + name + " GPA: " + gpa;
}
public double compareTo(Object other)
{
Student filler = (Student)other;
if(this.getGpa() < filler.getGpa())
return -1;
else if(this.getGpa() == filler.getGpa())
return 0;
else
return 1;
}
}

To answer your question directly, you need to change the return type of compareTo() from double to int.
There are also several other modifications you should make to improve your code:
implement Comparable<Student> instead of just Comparable. This makes it so you can write public int compareTo(Student other) and only allows calling compareTo() with other Student references.
Add #Override annotations before both toString() and compareTo(). This annotation helps you avoid some common errors which the compiler cannot catch.

compareTo method returns an int and not a double.
Also using an Override annotation helps to be sure that you are overriding the method correctly. So change this
public double compareTo(Object other)
to
#Override
public int compareTo(Object other)

public double compareTo(Object other)
should be
#Override
public int compareTo(T other)
Take a look at the Comparable interface. It requires a method called compareTo, that takes an argument of type T (generic parameter), that returns an int. The method you have created doesn't implement the method specified in the interface, which is why the Java compiler is complaining.
Since the Comparable interface is genericized, you should take advantage of generics and make your class implement Comparable<Student>. When you do that, the signature of compareTo becomes:
#Override
public int compareTo(Student other)
Which is better than a raw Object, since you don't have to cast, and more importantly, you don't accidentally end up passing in something that is not a Student.
One more thing: use the #Override annotation when you implement methods from the interface. Assuming you're using a halfway-decent IDE, you would have seen an error if you had:
#Override
public double compareTo(Object other)
Since there is no method with that signature in the interface.

Related

Comparing objects exercise (Java)

hopefully this doesn't make me seem to be an idiot but I seem to be failing on a simple exercise where I have to compare two objects to check if they are equal, my Java class is below along with the error message I'm getting from the exercise. Would anyone know how to solve it? Thanks in advance.
import java.util.Objects;
public class Person {
private String name;
private SimpleDate birthday;
private int height;
private int weight;
public Person(String name, SimpleDate birthday, int height, int weight) {
this.name = name;
this.birthday = birthday;
this.height = height;
this.weight = weight;
hashCode();
}
public String getName(){
return this.name;
}
public SimpleDate getBirthday(){
return this.birthday;
}
public Integer getHeight(){
return this.height;
}
public Integer getWeight(){
return this.weight;
}
// implement an equals method here for checking the equality of objects
#Override
public boolean equals(Object compared){
return this==compared;
}
}
Error message
Joshua Bloch in Effective Java gives guidelines on how to write a nice .equals(). Here's the excerpt directly from the book:
Use the == operator to check if the argument is a reference to this object.
Use the instanceof operator to check if the argument has the correct type.
Cast the argument to the correct type.
For each “significant” field in the class, check if that field of the argument matches the corresponding field of this object.
When you are finished writing your equals method, ask yourself three questions: Is it symmetric? Is it transitive? Is it consistent?
public boolean equals(Object o) {
if(o == this) {
return true;
}
if(!(o instance of Person)) {
return false;
}
//you comparing logic here
}
You have to make sure that equals follows its contract (it's an equivalence relation). See it's documentation for more details. Also, override the hashcode() method.
You equals method is written wrongly as it just compares the location of objects in memory. That's why your tests are failing.
You changed behaviour of equals to == here:
#Override
public boolean equals(Object compared){
return this==compared;
}
and now here is already an answer - https://stackoverflow.com/a/13387787/7505731

Problem with Array.sort() and objects in JAVA [duplicate]

I am not sure how to implement a comparable interface into my abstract class. I have the following example code that I am using to try and get my head around it:
public class Animal{
public String name;
public int yearDiscovered;
public String population;
public Animal(String name, int yearDiscovered, String population){
this.name = name;
this.yearDiscovered = yearDiscovered;
this.population = population; }
public String toString(){
String s = "Animal name: "+ name+"\nYear Discovered: "+yearDiscovered+"\nPopulation: "+population;
return s;
}
}
I have a test class that will create objects of type Animal however I want to have a comparable interface inside this class so that older years of discovery rank higher than low. I have no idea on how to go about this though.
You just have to define that Animal implements Comparable<Animal> i.e. public class Animal implements Comparable<Animal>. And then you have to implement the compareTo(Animal other) method that way you like it.
#Override
public int compareTo(Animal other) {
return Integer.compare(this.year_discovered, other.year_discovered);
}
Using this implementation of compareTo, animals with a higher year_discovered will get ordered higher. I hope you get the idea of Comparable and compareTo with this example.
You need to:
Add implements Comparable<Animal> to the class declaration; and
Implement a int compareTo( Animal a ) method to perform the comparisons.
Like this:
public class Animal implements Comparable<Animal>{
public String name;
public int year_discovered;
public String population;
public Animal(String name, int year_discovered, String population){
this.name = name;
this.year_discovered = year_discovered;
this.population = population;
}
public String toString(){
String s = "Animal name: "+ name+"\nYear Discovered: "+year_discovered+"\nPopulation: "+population;
return s;
}
#Override
public int compareTo( final Animal o) {
return Integer.compare(this.year_discovered, o.year_discovered);
}
}
While you are in it, I suggest to remember some key facts about compareTo() methods
CompareTo must be in consistent with equals method e.g. if two objects are equal via equals() , there compareTo() must return zero otherwise if those objects are stored in SortedSet or SortedMap they will not behave properly.
CompareTo() must throw NullPointerException if current object get compared to null object as opposed to equals() which return false on such scenario.
Read more: http://javarevisited.blogspot.com/2011/11/how-to-override-compareto-method-in.html#ixzz4B4EMGha3
Implement Comparable<Animal> interface in your class and provide implementation of int compareTo(Animal other) method in your class.See This Post
You would need to implement the interface and define the compareTo() method.
For a good tutorial go to - Tutorials point link
or
MyKongLink
Emp class needs to implement Comaparable interface so we need to Override its compateTo method.
import java.util.ArrayList;
import java.util.Collections;
class Emp implements Comparable< Emp >{
int empid;
String name;
Emp(int empid,String name){
this.empid = empid;
this.name = name;
}
#Override
public String toString(){
return empid+" "+name;
}
#Override
public int compareTo(Emp o) {
if(this.empid==o.empid){
return 0;
}
else if(this.empid < o.empid){
return 1;
}
else{
return -1;
}
}
}
public class JavaApplication1 {
public static void main(String[] args) {
ArrayList<Emp> a= new ArrayList<Emp>();
a.add(new Emp(10,"Mahadev"));
a.add(new Emp(50,"Ashish"));
a.add(new Emp(40,"Amit"));
Collections.sort(a);
for(Emp id:a){
System.out.println(id);
}
}
}
Possible alternative from the source code of Integer.compare method which requires API Version 19 is :
public int compareTo(Animal other) {
return Integer.valueOf(this.year_discovered).compareTo(other.year_discovered);
}
This alternative does not require you to use API version 19.
Use a Comparator...
public class AnimalAgeComparator implements Comparator<Animal> {
#Override
public int compare(Animal a1, Animal a2) {
...
}
}
This thing can easily be done by implementing a public class that implements Comparable. This will allow you to use compareTo method which can be used with any other object to which you wish to compare.
for example you can implement it in this way:
public String compareTo(Animal oth)
{
return String.compare(this.population, oth.population);
}
I think this might solve your purpose.

Why this Java Code is compiling successfully

I haven't overridden much of hashCode() and equals() methods so I may be wrong
My question is for the last line where
dep1.equals(emp2) is being compiled successfully(why) (I am expecting compilation error as they have different types) and after compiling I get following
15 15 false
where I am expecting 15 15 true since I am checking the hashcode in the equals method.
class Employee {
private String name;
private int id;
public Employee(String name, int id) {
this.name = name;
this.id = id;
}
public int hashCode() {
return this.id;
}
public boolean equals(Employee employee) {
return this.hashCode() == employee.hashCode();
}
public int getEmployeeId() {
return this.id;
}
}
class Department {
private String name;
private int id;
public Department(String name, int id) {
this.name = name;
this.id = id;
}
public int hashCode() {
return this.id;
}
public boolean equals(Department department) {
return this.hashCode() == department.hashCode();
}
public int getDepartmentId() {
return this.id;
}
}
public class JavaCollections {
public static void main(String args[]) {
Employee emp2 = new Employee("Second Employee", 15);
Department dep1 = new Department("Department One", 15);
System.out.println(dep1.hashCode()+" "+emp2.hashCode()+" " + dep1.equals(emp2));
}
}
First, for the reason why this compiles: all classes in Java inherit from java.lang.Object, which defines equals(Object) method, and provides a default implementation. This is the method that you call when you compare an Employee and a Department, not one of the overloads that you have provided.
Your equals code compiles fine, because the compiler does not know that you thought you were overriding equals when you actually didn't. The compiler thinks that you want to make a new method
public boolean equals(Department department)
to compare Department objects to other Department objects.
If you are writing a code that overrides a method of a superclass, add #Override annotation to it, like this:
#Override
public boolean equals(Department department)
Now the compiler will correctly complain to you that your method does not in fact override a method in its base class, alerting you to the problem at compile time.
To fix your code change the signatures of equals to take Object, add #Override, check for null and for the correct type, do the cast, and then do the actual comparison:
#Override
public boolean equals(Department obj) {
if (obj == null || !(obj instanceof Department)) {
return false;
}
Department dept = (Department)obj
return dept.id == id;
}
Note: Implementing equals like this
return this.hashCode() == department.hashCode();
is very fragile. Although it works in your case, when hash code is a unique ID of the object, this wouldn't survive a code refactoring when hashCode is replaced with some other implementation, for example, an implementation that considers both id and name. If you want to rely on comparing IDs, compare IDs directly, without calling hashCode to get them.
That's because both of classes Employee and Department still have not overriden methods public boolean equals(Object obj) inherited from Object class.
Exactly this method is invoked in dep1.equals(emp2), not public boolean equals(Department department).
More specifically, read JLS:
An instance method mC declared in or inherited by class C, overrides from C another method mA declared in class A, iff all of the following are true:
...
The signature of mC is a subsignature (§8.4.2) of the signature of mA.
In this case boolean equals(Department department) is not subsignature of boolean equals(Object obj).
First, this code dep1.equals(emp2) calls default implementation of Object class.
Second, U didnt overrides the default implementation in both of your class becoz u cant override equal method for specific customizied types.
If u need ur answer to be 15 15 true
replace
public boolean equals(Department department) {
return this.hashCode() == department.hashCode();
}
by
#override
public boolean equals(Object department) {
return this.hashCode() == department.hashCode();
}

Trying to implement the interface Comparable

just wondering what this error means and how I should fix this.
Error: The type Student must implement the inherited abstract method java.lang.Comparable.compareTo(java.lang.Object)
I am trying to implement this so I can use the class's compareTo Method.
Thanks so much for your help!
import java.util.*;
import java.io.*;
public class Student implements Comparable
{
private String name;
private double gpa;
public Student()
{
name = "";
gpa = 0.0;
}//end default constructor
public Student(String n, double g)
{
name = n;
gpa = g;
}//end two arg constructor
public double getGPA()
{
return gpa;
}
public String getName()
{
return name;
}
public void setGPA(double g)
{
this.gpa = g;
}
public void setName(String n)
{
this.name = n;
}
public String toString()
{
return " Name: " + name + " GPA: " + gpa;
}
public static void compareTo()
{
}
}//end class
All you have to do is implement the comparable interface and override the compareTo() method in the class you wanted to be sorted. Inside the compareTo method you must mention on which basis your object should be sorted. The below code will be helpful in this:
public class Student implements Comparable<Student>
{
private String name;
private double gpa;
public Student()
{
name = "";
gpa = 0.0;
}//end default constructor
public Student(String n, double g)
{
name = n;
gpa = g;
}//end two arg constructor
public double getGPA()
{
return gpa;
}
public String getName()
{
return name;
}
public void setGPA(double g)
{
this.gpa = g;
}
public void setName(String n)
{
this.name = n;
}
public String toString()
{
return " Name: " + name + " GPA: " + gpa;
}
public Integer compareTo(Student student)
{
// if object is getting sorted on the basis of Name
return this.getName().compareTo(student.getName())
// if object is getting sorted on the basis of gpa
return Double.valueOf(this.gpa).compareTo(Double.valueOf(student.getGPA()));
}
}//end class
Since you are using primitive data type double instead of Object Double so we need to get the object using Double.valueOf(this.gpa)
You should use only one return statement as per your requirement.
You have to make the following changes to your code in order to implement the Comparable interface correctly.
(1) Specify the type of object your class is comparable with:
public class Student implements Comparable<Student>
(2) And the corresponding signature of the compareTo method is as follow:
public int compareTo(Student other)
And of course you have to implement the body of the compareTo method too.
If the this instance is "smaller" than the argument other then compareTo should return a negative number.
If the this instance is "larger" than the argument other then compareTo should return a positive number.
If the this instance is considered to be "of the same value" as the argument other then compareTo should return 0.
You may refer to the official java document for more information about the implementation details.
Note that Interface Comparable<T> is a generic interface. Here T is type (Class, Interface mostly). You want to compare Student with another type (Student).
So you have to pass type(T) Student to Comparable<T>.
Hence you change it to
public class Student implements Comparable<Student>
Another point you have to implement the Comparable<T> interface as same method signature and return type to Student class.
public int compareTo(Student anotherStudent)
You have written
public static void compareTo()
which not follow the interface Comparable<T> method signature and return type in Student class.
Here you should implement your domain specific logic. I don't know how you want to implement it ? You can compare the name alphabetically or base on their CGPA.

Java, how to inherit methods from abstract class

I have an abstract class Person and and interface comparable, which is also used for some other part of the program. Currently I have a method compareTo() in Person. When I try to compile, I get :
The type Student must implement the inherited abstract method
Comparable<Person>.compareTo(Person, Person)
What exactly do I have to do? I don't wont to implement this method in any of the subclasses, because I need this method for all of them, Student, Tutor, Professor, etc... Is there a better way of doing this?
Interface:
interface Comparable<Element> {
public int compareTo(Element nodeA, Element nodeB);
}
Abstract class Person:
abstract class Person implements Comparable<Person> {
protected String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String newName) {
name = newName;
}
public String toString() {
return name;
}
public int compareTo(Person personB) {
int comp = this.name.compareTo(personB.getName());
return comp;
}
}
And class Student
class Student extends Person implements Comparable<Person> {
private int id;
public Student(String name, int id) {
super(name);
this.id = id;
}
public int getID() {
return id;
}
public void setID(int newID) {
id = newID;
}
public String toString() {
return id + ", " + name;
}
}
Change your interface from:
interface Comparable<Element>
{
public int compareTo(Element nodeA, Element nodeB);
}
to:
interface Comparable<Element>
{
public int compareTo(Element nodeA);
}
And make your Person class be defined as:
abstract class Person implements Comparable<? extends Person> { /* ... */ }
And make your Student (and other Person-subclasses be):
class Student extends Person { /* ... */ }
That is all.
Your Comparable interface has a method compareTo(Element nodeA, Element nodeB). This method is not defined in Student, and it's not defined in Person either. Person has the following method:
public int compareTo(Person personB)
, which doesn't override compareTo(Person nodeA, Person nodeB)
Why are you redefining the standard java.util.Comparable interface?
You should implement the method as it appears in the interface, i.e. with two arguments
public int compareTo(Person nodeA, Person nodeB)
To avoid such problems in the future use the #Override annotation:
#Override
public int compareTo(Person nodeA, Person nodeB)
This will cause a compilation error if you try to override a method, but make a mistake in its signature.
Also, consider using Java's standard Comparable.
Your Comparable<Element> class declares a method public int compareTo(Element nodeA, Element nodeB);, but in your Person class, you implement public int compareTo(Person personB), which is not the same method signature.
You need to either implement public int compareTo(Person personA, Person personB), or alter your Comparable<Element> class's method definition to be public int compareTo(Element other); to override the core Comparable class's compareTo method.
Also, as #murat mentions below in the comment, using the #Override annotation would help you out (assuming you're on Java version 1.5 or higher). If you add #Override to a method that you're not actually overriding from a superclass (such as your two-argument compareTo method), then it will be a compiler error.
You need to implement
public int compareTo(Person nodeA, Person nodeB)
In your Person class. Currently you only have:
public int compareTo(Person personB)
You need to create a compareTo method in the Student class.
interface Comparable<Element> {
public int compareTo(Element nodeA, Element nodeB);
}
It makes sense if it was either:
interface Comparator<Element> { //comparator compares two instances of same type
public int compare(Element nodeA, Element nodeB);
}
or (has to be something like this for your case):
interface Comparable<Element> { //comparable compares itself with another instance of same type
public int compareTo(Element that);
}
But for both cases, you should use the standard Java interfaces: Even though you are only using Comparable also see Comparator.

Categories