简体   繁体   中英

strange issue with Generic type inference

I'm having a strange behaviour with Generics I'm using Java8.

Here is a small sample code to demonstrate the problem Following code works fine without any issues with type inference. where, SpecificError is a subtype of GenericError.

public GenericType<AbstractError> method{
   Optional<SpecificError> error = Optional.of(new SpecificError());
   if (error.isPresent()) {
    return GenericType.error(error.get());
  } else {
     // return something else
  }
}

I have lot of this places in the code, where I had to do this if/else checks with optional, I decided to make a new function which receives the Optional, checks for presence and returns the Generic type object New function code:

public static <R extends AbstractError> GenericType<R> shortcut(Optional<R> error) {
    if (error.isPresent()) {
      return GenericType.error(error.get());
    } else {
    // something else
    }
}

This is new code calling the above function:

public GenericType<AbstractError> method{

       Optional<SpecificError> error = Optional.of(new SpecificError());
       return GenericType.shortcut(error);
    }

And strangely this does not work and breaks the following compilation error:

[ERROR]     inferred: AbstractError

[ERROR]     equality constraints(s): AbstractError, SpecificError

I just do not understand, why this won't work. The only thing, I have done is to make a small function which the job of doing isPresent check on Optional, everything else is the same. Why can't Java see that SpecificError is subtype of AbstractError

From the method method() , you are calling GenericType.shortcut(error) , where error is of the type Optional<SpecificError> . shortcut demands a type argument R , which you are trying to fulfill with R = SpecificError . So you are trying to return a GenericType<SpecificError> , but your method signature declares that it returns a GenericType<AbstractError> .

A GenericType<SpecificError> is not a GenericType<AbstractError> , because generics are invariant .

You could fix this by replacing

Optional<SpecificError> error = Optional.of(new SpecificError());

with

Optional<AbstractError> error = Optional.of(new SpecificError());

As you declare the GenericType as <R extends AbstractError> at shortcut()

It is now forced to return a subtype . That is why the compiler is creating issues.

The concept witnessed here is Type Equality Constraint , covered under Java Generics

Thing should get going if you change the method signature to

public static <R> GenericType<R> shortcut(Optional<R> error) { // remove extends AbstractError
public GenericType<AbstractError> method{
   Optional<SpecificError> error = Optional.of(new SpecificError());
   return GenericType.shortcut(error);
}

public static <R extends AbstractError> GenericType<R> shortcut(Optional<R> error) {

shortcut needs an Optional parameter whose type parameter matches the return type.

But yours doesn't: SpecificError isn't the same as AbstractError .

All you need is for error to be R or a subclass, so add an upper bound to the parameter type:

Optional<? extends R> error

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