Marco
Marco

Reputation: 121

Java bounded parameters in generic methods

I have tested some things with bounded parameters in generic methods and I discovered some strange behavior.
It would be great If anybody could explain the two errors in the following code snippet.

Imagine there are two classes Class1 and Class2 both extend from a BaseClass. Class2 implements an Interface.

In Class1, I have a method which returns an instance of Class2 in the following way:

public class Class2 extends BaseClass implements Interface {

    @Override
    public void method() {
        System.out.println("test"); //$NON-NLS-1$
    }
}

public class Class1 extends BaseClass {

    public <T extends BaseClass & Interface> T getTwo() {
        return new Class2();
        // Error: Type mismatch: cannot convert from Class2 to T
    }

    public static void main(String[] args) {
        Interface two = new Class1().getTwo();
        // Error: Bound mismatch: The generic method getTwo() of type Class1 is
        // not applicable for the arguments (). The inferred type Interface is
        // not a valid substitute for the bounded parameter <T extends BaseClass
        // & Interface>
        System.out.println(two);
    }
}

Upvotes: 10

Views: 1611

Answers (2)

meriton
meriton

Reputation: 70584

The first compilation error occurs because type parameters declared by methods are specified by the caller, not the method implementation. That is, given

class Class3 extends BaseClass implements Interface { ... }

a caller may write

Class3 c3 = new Class1().<Class3>getTwo();

, but the method implementation returns a Class2, which isn't a subtype of T = Class3.

The second compilation error occurs because type parameters that aren't explicitly specified by the caller are inferred from method arguments and the type of the variable the method return value is assigned to. This inference fails here. The usual workaround, recommended by the Java Language Specification, is to specify the type parameters explicitly in such cases (type inference is intended as a convenience for simple cases; it doesn't aim to cover all cases).

As for how to properly declare this type parameter, I'd need to know what you are trying to accomplish with these declarations.

Upvotes: 5

Bohemian
Bohemian

Reputation: 425298

Why use generics for the method getTwo, when you know it's a Class2? Simply do this:

public Class2 getTwo() {
    return new Class2();
}

If you're overriding a method public <T extends BaseClass & Interface> T getTwo(), the compiler will allow you to declare your impl as public Class2 getTwo() when your T for your impl is Class2

Upvotes: 4

Related Questions