简体   繁体   中英

Seeking clarification regarding type erasure and type inference

class Undoable<T> {
  T value;
  Deque<Object> history;
      
  Undoable(T t, Deque<Object> history) {
    this.value = t;
    this.history = history;
  }
  
  static <T> Undoable<T> of(T t) {
    return new Undoable<T>(t, new LinkedList<Object>());
  }

  public <R> Undoable<R> flatMap(Function<T, Undoable<R>> mapper) {
    Undoable<R> r = mapper.apply(value);
    Deque<Object> newHistory = new LinkedList<>();
    newHistory.addAll(history);
    newHistory.addAll(r.history);
    return new Undoable<R>(r.value, newHistory);
  }

  public <R> Undoable<R> undo() {
    Deque<Object> newHistory = new LinkedList<>(this.history);
    R r;
    try {
      r = (R)newHistory.removeLast(); //line A
    } catch (NoSuchElementException e) {
      throw new CannotUndoException();
    }
    return new Undoable<R>(r, newHistory);
  }
}

Given the code snippet above, let say we leave Line A as it is and ignore the compilation warning. What would happen if we

Undoable<Integer> i = Undoable.of("hello").flatMap(s -> {
    Deque<Object> history;
    history = new LinkedList<>();
    history.add(s);
    return new Undoable<Integer>(s.length(), history);
});
Undoable<Double> d = i.undo();

I get that Undoable<Integer> and Undoable<Double> erases to Undoable . But what does R in the undo() method become? Does it infer to be Double since Double is the target type of that method call?

I've tried running the code on my machine and it runs fine but I have no idea why. Can anyone shed some light? Thanks a ton!

The R type it will become Object , even when inferred during the method call, this is because of R been of no use, since you never explicit declared it, like this i.<Double>undo() , in most use cases, parametric types are used in methods to infer the types of the method parameters. About your code flow, even with a Undone the d.value is a string, it's because d Undone type will be compiled to object, since the R type could be anything, doesn't have how to compare, in compile time, the type inferred result of the method call with your declaration. If you put Undone<Double> d = i.<String>undo() it will throw an error, otherwise if you don't explicit declare, never will throw a cast exception.

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