Implementing Comparable, compareTo name clash: "have the same erasure, yet neither overrides the other"

18,797

Solution 1

The offending methods are:

@Override
public int compareTo(Real other) { ... }

public int compareTo(Object other) { ... }

These methods have the same erasure, meaning that once the compiler strips out generic type information, there will no longer be a way to differentiate them at runtime.

Your options are to either remove the compareTo(Object other) overload, or for Real to implement Comparable<Object>.

Since it looks like the implementations of all your compareTo overloads just instantiate a new Real and pass it to compareTo(Real), I'd suggest removing them and leaving that conversion up to the caller:

Real real = ...;
Object compared = ...;

Real comparedAsReal = new Real(compared);
int result = real.compareTo(comparedAsReal);

Solution 2

Since you want to be able to compare Real object to Object, you may just replace the implements Comparable<Real> with implements Comparable<Object>. This would be consistent with Comparable<T> javadoc which says that <T> the type of objects that this object may be compared to.

Then you just have to change your current code to :

// No more @Override
public int compareToReal(Real other)
{
  // Logic.
}
public int compareTo(char givenValue) 
{ return compareToReal(new Real(givenValue)); }
public int compareTo(char[] givenValue) 
{ return compareToReal(new Real(givenValue)); }
public int compareTo(char[] givenValue, int offset, int count) 
{ return compareToReal(new Real(givenValue, offset, count)); }
public int compareTo(double givenValue) 
{ return compareToReal(new Real(givenValue)); }
public int compareTo(float givenValue) 
{ return compareToReal(new Real(givenValue)); }
public int compareTo(int givenValue) 
{ return compareToReal(new Real(givenValue)); }
public int compareTo(long givenValue) 
{ return compareToReal(new Real(givenValue)); }
@Override
public int compareTo(Object other) 
{ return compareToReal(new Real(other.toString())); }

Solution 3

This is a side effect of Java generics type-erasure.

You are implementing a generic interface, Comparable, but this its unique method, once generic type erased will become compareTo(Object), hence it clashes with your own compareTo(Object).

Here is a minimal code to reproduce:

class Real implements Comparable<Real>
{
    public int compareTo(Object o)
    {
        return 0;
    }

    @Override
    public int compareTo(Real o)
    {
        return 0;
    }       
}
Share:
18,797

Related videos on Youtube

Jxek
Author by

Jxek

Updated on September 15, 2022

Comments

  • Jxek
    Jxek over 1 year

    I'd like to have a compareTo method that takes a Real (a class for working with arbitrarily large and precise real numbers [well, as long as it's less than 2^31 in length at the moment]) and a compareTo method that takes an Object, but Java isn't letting me and I'm not experienced enough to know why.

    I just tried to modify the class to implement Comparable and I got these error messages below. I don't really understand what the error messages mean but I know it's got something to do with the horrible way I'm trying to give the class some flexibility with all the different method signatures for every single method I make, and I can fix it by removing the compareTo(Object other) method, but I would ideally like to keep it. So what I'm really asking is: Is there a way to make these error messages disappear without removing the compareTo(Object other) method and what exactly do these errors mean?

    Also, I know there are already some built-in Java classes like BigInteger and things like that for what I'm trying to use this class for but I'm doing it for fun/satisfaction for use with Project Euler (https://projecteuler.net/).

    Jake@Jake-PC /cygdrive/c/Users/Jake/Documents/Java/Mathematics
    $ javac Real.java
    Real.java:377: error: name clash: compareTo(Real) in Real overrides a method whose erasure is the same as another method, yet neither overrides the other
      public int compareTo(Real other)
                 ^
      first method:  compareTo(Object) in Real
      second method: compareTo(T) in Comparable
      where T is a type-variable:
        T extends Object declared in interface Comparable
    Real.java:440: error: name clash: compareTo(Object) in Real and compareTo(T) in Comparable have the same erasure, yet neither overrides the other
      public int compareTo(Object other)
                 ^
      where T is a type-variable:
        T extends Object declared in interface Comparable
    2 errors
    

    These are the compareTo methods:

      @Override
      public int compareTo(Real other)
      {
        // Logic.
      }
      public int compareTo(char givenValue) 
      { return compareTo(new Real(givenValue)); }
      public int compareTo(char[] givenValue) 
      { return compareTo(new Real(givenValue)); }
      public int compareTo(char[] givenValue, int offset, int count) 
      { return compareTo(new Real(givenValue, offset, count)); }
      public int compareTo(double givenValue) 
      { return compareTo(new Real(givenValue)); }
      public int compareTo(float givenValue) 
      { return compareTo(new Real(givenValue)); }
      public int compareTo(int givenValue) 
      { return compareTo(new Real(givenValue)); }
      public int compareTo(long givenValue) 
      { return compareTo(new Real(givenValue)); }
      public int compareTo(Object other) 
      { return compareTo(new Real(other.toString())); }
    

    and the constructors just in case you need them:

      public Real(String givenValue)
      {
        // Logic.
      }
      public Real(char givenValue) 
      { this(String.valueOf(givenValue)); }
      public Real(char[] givenValue) 
      { this(String.valueOf(givenValue)); }
      public Real(char[] givenValue, int offset, int count) 
      { this(String.valueOf(givenValue, offset, count)); }
      public Real(double givenValue) 
      { this(String.valueOf(givenValue)); }
      public Real(float givenValue) 
      { this(String.valueOf(givenValue)); }
      public Real(int givenValue) 
      { this(String.valueOf(givenValue)); }
      public Real(long givenValue) 
      { this(String.valueOf(givenValue)); }
      public Real(Object other) 
      { this(other.toString()); }