steven35
steven35

Reputation: 4017

Generic method only compiles with one argument

The below code will not compile, it says that the method is not applicable for the arguments. The interesting thing is that if I remove one of the arguments (doesn't matter which) then it compiles fine.

public class Test1 {
    static Collection<? extends Shape> someColl = new ArrayList<Shape>();

    public static void main(String args[]) {
        new Test1();
    }

    public static void Main(String[] args) {
        addShape(someColl, new Circle()); //compilation error
    }

    static <T extends Shape> void addShape(Collection<T> shapes, T shape) {
        shapes.add(shape);
    }

    abstract class Shape {

    }

    class Rect extends Shape{

    }

    class Circle extends Shape {

    }
}

If I remove one of the method arguments and change it to

addShape(someColl)

and

static <T extends Shape> void addShape(Collection<T> shapes)

OR change it to

addShape(new Circle())

and

static <T extends Shape> void addShape(T shape)

Then it's fine. What's happening here?

Upvotes: 0

Views: 73

Answers (2)

bodyjares
bodyjares

Reputation: 440

Maybe you just need to use an interface to be able to add Rects and Cicles in a same collection. If it's what you're trying to do:

public class Test1 {
   static Collection<Shape> someColl = new ArrayList<Shape>();

   public static void main(String[] args) {
       Test1 t = new Test1();
       Circle c = t.new Circle();
       Rect r = t.new Rect();
       addShape(someColl, c);
       addShape(someColl, r);
   }

   static boolean addShape(Collection<Shape> someColl2, Shape shape) {
       return someColl2.add(shape);
   }

   interface Shape {

   }

   abstract class AbstractShape {

   }

   class Rect extends AbstractShape implements Shape{

   }

   class Circle extends AbstractShape implements Shape {

   }
}

Upvotes: 0

Thomas
Thomas

Reputation: 88707

The problem is that when you call addShape(someColl, new Circle()); there are two different definitions of T

  • ? extends Shape from Collection<? extends Shape> someColl
  • Circle from the second parameter

The other problem with that call is that T needs to be a concrete type for the second parameter, i.e. you can't define it as ? extends Shape shape as would be the result when infering T from Collection<? extends Shape>.

The method being called addXxxx suggests you want to add the shape passed as the second parameter to the collection. That, however, won't work with a Collection<? extends Shape> since the compiler can't know whether a Circle or any other shape type is allowed.

Assume you'd change the method to accept Shape as the second parameter: you could pass a Collection<Rect> and a Circle which would not fit.

Your best bet in your case would be to change the definition of someColl to Collection<Shape> since that's what you do with ArrayList<Shape> anyways. The compiler would then infer T to be Shape and the call should compile.

Upvotes: 1

Related Questions