Java Generics: Multiple Inheritance in Bounded Type Parameters <T extends A & I>

scravy picture scravy · Mar 22, 2012 · Viewed 16.8k times · Source

I am about to create a factory which creates objects of a certain type T which extends a certain class A and another interface I. However, T must not be known. Here are the minimum declarations:

public class A { }
public interface I { }

This is the factory method:

public class F {
    public static <T extends A & I> T newThing() { /*...*/ }
}

This compiles all fine.

When I try to use the method the following works fine:

A $a = F.newThing();

...while this does not:

I $i = F.newThing();

The compiler complains:

Bound mismatch: The generic method newThing() of type F is not applicable for the arguments (). The inferred type I&A is not a valid substitute for the bounded parameter

I can't understand why. It is clearly stated that "newThing returns something of a certain type T which does extend the class A and implement the interface I". When assigning to A everything works (since T extends A) but assigning to I does not (because of what?, clearly the thing returned is both an A and an I)

Also: When returning an object, say B of the type class B extends A implements I, I need to cast it to the return type T, although B matches the bounds:

<T extends A & I> T newThing() {
    return (T) new B();
}

However, the compiler does not throw any warnings like UncheckedCast or the like.

Thus my question:

  • What is going wrong here?
  • Is there an easy away to achieve the desired behavior (i.e. assigning to a variable of static type A or I), like there is in solving the return-type-problem by casting, in the factory method?
  • Why does the assignment to A work, while to I does not?

--

EDIT: Here the complete code snippet which totally works using Eclipse 3.7, project set up for JDK 6:

public class F {
    public static class A { }
    public static interface I { }

    private static class B extends A implements I {  }

    public static <T extends A & I> T newThing() {
        return (T) new B();
}

    public static void main(String... _) {
        A $a = F.newThing();
        // I $i = F.newThing();
    }
}

EDIT: Here is a complete example with methods and invocation which does work at runtime:

public class F {
    public static class A {
        int methodA() {
            return 7;
        }
    }
    public static interface I {
        int methodI();
    }

    private static class B extends A implements I {
        public int methodI() {
            return 12;
        }
    }

    public static <T extends A & I> T newThing() {
        return (T) new B();
    }

    public static void main(String... _) {
        A $a = F.newThing();
        // I $i = F.newThing();
        System.out.println($a.methodA());
    }
}

Answer

Thomas picture Thomas · Mar 22, 2012

As for the second question:

Consider this case:

 class B extends A implements I {}
 class C extends A implements I {}

Now, the following uses type inference:

<T extends A & I> T newThing() {
  return (T) new B();
}

So you could call this:

C c = F.newThing(); //T would be C here

You see that T could be anything that extends A and I you can't just return an instance of B. In the case above the cast could be written as (C)new B(). This would clearly result in an exception and thus the compiler issues a warning: Unchecked cast from B to T - unless you're supressing those warnings.