简体   繁体   中英

Java Generic type inference derived from method return type

public class TestCase {
    public static String compiles() {
        return getAction();
    }

    /*
    public static String doesntCompile1() {
        return (String) getAction();
    }

    public static String doesntCompile2() {
        return TestCase.<String> getAction();
    }
    */

    public static <T extends javax.swing.Action> T getAction() {
        return (T) null;
    }
}

Should this be considered a bug in javac v1.6.0_22 and jdt v3.7.1? To me it seems that way since in the other cases, the compiler actually finds the potential ClassCastException. In the compiles method, this will throw at ClassCastException at runtime.

The original code that brought this exemple didn't compile in javac, printing the following exception. Unfortunately, the exemple code I provided for some reason will not generate this error.

type parameters of <T>T cannot be determined;
no unique maximal instance exists for type variable T with upper bounds

I would expect a good compiler to be able to detect the error, but as an optimization. You present a specific case of a more general case like this:

public class TestCase {
    public static TypeA methodA() {
        return methodB();
    }

    public static <T extends TypeB> T methodB() {
        return (T) null;
    }
}

Now, in general there's nothing wrong with that, provided:

  1. If TypeA and TypeB are both classes then TypeB is a superclass of TypeA.
  2. TypeA or one of TypeA's subtypes inherits from TypeB.

Now the key thing that the compiler isn't checking is #2, when it can in this case. But that is only because String is a final class. If the class isn't final, #2 will always be true because the potential subclasses aren't known at compile time.

Imagine that instead of String , you used CharSequence . Then I would expect all three to compile. However, I cannot explain why in your example the second and third method do not compile.

Edit

And now I have tried it with javac , and have found that the first method does not compile either. The above accepts the premise of your question which seems to be false. I get the misleading compile error

Incompatible types. Required: java.lang.String . Found: T .

This answer doesn't answer the full question, but rather explains why it doesn't work but something like this:

public static CharSequence compiles() {
    return (CharSequence)getAction();
}

does.

I don't understand what the problem/question is here. The errors you are getting are both obvious and expected.

For the doesntCompile1 method, my compiler tells me

Cannot cast from Action to String

which is totally expected - we know the method returns a T which is an Action and we know an Action can't be cast to a String .

For the doesntCompile2 method, my compiler tells me

Bound mismatch: The generic method getAction() of type TestCase is not applicable for the arguments (). The inferred type String is not a valid substitute for the bounded parameter

which is basically the same reason as above

What did you expect it to do?

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