Reputation: 2413
I have
class Shape implements Comparable <Shape>
and
class Square extends Shape
I wrote a generic method for finding the maximum element within an array:
public static <S extends Comparable<S>> S findMax(S[] arr)
{
//blablabla...
return maxS;
}
These two calls give me no errors and do what they're supposed to:
Shape maxShape = findMax(new Shape[]{new Shape(1), new Shape(2), new Shape(3)});
Square maxSquare = findMax(new Square[]{new Square(1), new Square(2), new Square(3)});
Therefore, it seems reasonable to me that since Shape
implements Comparable<Shape>
and Square
extends Shape
, Square
s should also be comparable, a.k.a. Square
somehow automatically implements Comparable<Square>
through inheritance (particularly by inheriting compareTo(Shape s)
).
However, according to my textbook, this is not the case: here "all we know is that Square implements Comparable<Shape>
; thus a Square
IS-A Comparable<Shape>
, but IS-NOT-A Comparable<Square>
", and it suggests a better method signature instead:
public static <S extends Comparable<? super S>>
.
Then why does my public static <S extends Comparable<S>>
give me no problem?
-----------------------------UPDATE (SOURCE CODE)------------------------------
public class Shape implements Comparable<Shape>{
protected int area;
public Shape (int i)
{
this.area=i;
}
public String toString()
{
return area+"";
}
public static void main(String[] args)
{
System.out.println("Bigger shape: "+findMax(new Shape[] {new Shape(2),new Shape(3)}));
System.out.println("Bigger square: "+findMax(new Square[] {new Square(2),new Square(3)}));
}
public int getValue()
{
return area;
}
@Override
public int compareTo(Shape sh) {
return Integer.valueOf(area).compareTo(sh.getValue());
}
public static <N extends Comparable<N>> N findMax(N[] arr)
{
int maxIdx=0;
for (int i=1; i<arr.length; i++)
if (arr[i].compareTo(arr[maxIdx])>0)
maxIdx=i;
return arr[maxIdx];
}
}
class Square extends Shape
{
public Square(int i)
{
super(i);
}
public int compareTo(Shape sh)
{
return Integer.valueOf(area%3).compareTo(sh.getValue()%3);
}
}
And the output I get is
Bigger shape: 3
Bigger square: 2
Lesson learned: the answer to the original question is no. As Tagir Valeev pointed out, it is permissible to call findMax
on Square[]
without assignment due to the covariant nature of Shape[]
.
Upvotes: 4
Views: 87
Reputation: 100329
Actually your code does not compile. Javac 1.7:
> "C:\Program Files\Java\jdk1.7.0_80\bin\javac.exe" GenericTest.java
GenericTest.java:32: error: method findMax in class GenericTest cannot be applied to given types;
Square maxSquare = findMax(new Square[]{new Square(1), new Square(2), new Square(3)});
^
required: S[]
found: Square[]
reason: inferred type does not conform to declared bound(s)
inferred: Square
bound(s): Comparable<Square>
where S is a type-variable:
S extends Comparable<S> declared in method <S>findMax(S[])
1 error
Javac 1.8:
>"C:\Program Files\Java\jdk1.8.0_40\bin\javac.exe" GenericTest.java
GenericTest.java:32: error: incompatible types: inference variable S has incompatible bounds
Square maxSquare = findMax(new Square[]{new Square(1), new Square(2), new Square(3)});
^
equality constraints: Shape
upper bounds: Square,Comparable<S>
where S is a type-variable:
S extends Comparable<S> declared in method <S>findMax(S[])
1 error
ECJ 3.10.2:
>java -jar org.eclipse.jdt.core_3.10.2.v20150120-1634.jar -source 1.7 GenericTest.java
----------
1. ERROR in C:\projects\Test\src\GenericTest.java (at line 32)
Square maxSquare = findMax(new Square[]{new Square(1), new Square(2), new Square(3)});
^^^^^^^
Bound mismatch: The generic method findMax(S[]) of type GenericTest is not applicable for the arguments (GenericTest.Square[]).
The inferred type GenericTest.Square is not a valid substitute for the bounded parameter <S extends Comparable<S>>
----------
1 problem (1 error)
All compilers produce correct error message as expected. If you declare findMax
method as public static <S extends Comparable<? super S>> S findMax(S[] arr)
, then the error message correctly disappears.
Update after you posted the complete code the problem becomes clear. The difference is that you don't assign the result of findMax
to the variable:
System.out.println("Bigger shape: "+findMax(new Shape[] {new Shape(1),new Shape(3)}));
System.out.println("Bigger square: "+findMax(new Square[] {new Square(3),new Square(2)}));
So in both cases <S>
is inferred to Shape
as Square[]
type IS-A Shape[]
type.
Upvotes: 3