Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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());
    }
}
like image 230
scravy Avatar asked Mar 22 '12 14:03

scravy


People also ask

What are bounded type parameters in generic?

Whenever you want to restrict the type parameter to subtypes of a particular class you can use the bounded type parameter. If you just specify a type (class) as bounded parameter, only sub types of that particular class are accepted by the current generic class. These are known as bounded-types in generics in Java.

How do you declare a generic bounded type parameter in Java?

To declare a bounded type parameter, list the type parameter's name, followed by the extends keyword, followed by its upper bound, which in this example is Number . Note that, in this context, extends is used in a general sense to mean either "extends" (as in classes) or "implements" (as in interfaces).

Is it possible to declared a multiple bounded type parameter?

Multiple BoundsBounded type parameters can be used with methods as well as classes and interfaces. Java Generics supports multiple bounds also, i.e., In this case, A can be an interface or class. If A is class, then B and C should be interfaces. We can't have more than one class in multiple bounds.

What is the need of generics What are the bounded types in generic classes?

Generics means parameterized types. The idea is to allow type (Integer, String, … etc., and user-defined types) to be a parameter to methods, classes, and interfaces. Using Generics, it is possible to create classes that work with different data types.


1 Answers

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.

like image 78
Thomas Avatar answered Sep 18 '22 14:09

Thomas