javac error: inconvertible types with generics?

2019-01-31 13:06发布

问题:

There are several other SO questions talking about generics compiling OK w/ Eclipse's compiler but not javac (i.e. Java: Generics handled differenlty in Eclipse and javac and Generics compiles and runs in Eclipse, but doesn't compile in javac) -- however this looks like a slightly different one.

I have an enum class:

public class LogEvent {
   public enum Type {
       // ... values here ...
   }
   ...
}

and I have another class with a method that takes in arbitrary objects of types descended from Enum:

@Override public <E extends Enum<E>> void postEvent(
    Context context, E code, Object additionalData) 
{
    if (code instanceof LogEvent.Type)
    {
        LogEvent.Type scode = (LogEvent.Type)code;
    ...

This works fine in Eclipse, but when I do a clean built with ant, I am getting a pair of errors, one on the instanceof line, the other on the casting line:

443: inconvertible types
    [javac] found   : E
    [javac] required: mypackage.LogEvent.Type
    [javac]         if (code instanceof LogEvent.Type)
    [javac]             ^

445: inconvertible types
    [javac] found   : E
    [javac] required: com.dekaresearch.tools.espdf.LogEvent.Type
    [javac]             LogEvent.Type scode = (LogEvent.Type)code;
    [javac]                                                  ^

Why does this happen, and how can I get around this problem so it will compile properly?

回答1:

I don't know why it's happening, but a workaround is easy:

@Override public <E extends Enum<E>> void postEvent(
    Context context, E code, Object additionalData) 
{
    Object tmp = code;
    if (tmp instanceof LogEvent.Type)
    {
        LogEvent.Type scode = (LogEvent.Type)tmp;
    ...

It's ugly, but it works...



回答2:

Perhaps it is because you've declared E as something that extends Enum<E>. I can't say I understand it completely, but it looks like it limits the set of types to some subset that can't include LogEvent.Type for some reason. Or maybe it's just a bug in the compiler. I'd be happy if someone could explain it more clearly, but here is what you can do:

public <E extends Enum<?>> void postEvent(E code) 
{
    if (code instanceof LogEvent.Type)
    {
        LogEvent.Type scode = (LogEvent.Type)code;
        ...
    }
    ...

This works and it is more elegant than just casting to an Object.



回答3:

I had a similar problem and upgraded from jdk1.6.0_16 to jdk1.6.0_23 and it went away without any code changes.



回答4:

In order to use instanceof both operands have to inherit/implement the same class/interface.
E just can't be cast to LogEvent.Type

I don't know what your full method looks like, but this should solve your issue by using interfaces and not Generics.

public interface EventType { }
public class LogEvent  {
    public enum Type implements EventType {}
}

public void postEvent(Context context, EventType code, Object additionalData) {
    if(code instanceof LogEvent.Type) {
    }
}