简体   繁体   中英

Does a subtype “inherit” generic interface parameterized with that particular subtype (Java)?

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, aka 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>> 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[] .

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) 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM