【问题标题】:Seeking clarification regarding type erasure and type inference寻求关于类型擦除和类型推断的澄清
【发布时间】:2021-04-26 06:37:26
【问题描述】:
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);
  }
}

鉴于上面的代码 sn-p,假设我们将 A 行保持原样并忽略编译警告。如果我们会发生什么

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();

我知道Undoable&lt;Integer&gt;Undoable&lt;Double&gt; 会擦除为Undoable。但是undo() 方法中的R 会变成什么?由于Double 是该方法调用的目标类型,它是否推断为Double

我试过在我的机器上运行代码,它运行良好,但我不知道为什么。任何人都可以解释一下吗?非常感谢!

【问题讨论】:

  • 既然我能理解,是的,它会从 Integer 转换为 Double,尝试用不同的东西声明 d 变量,看看它会抛出一个错误。
  • 对,另一个问题是这个问题的更一般的变体。我对类型推断和类型擦除的工作方式感到困惑。最初,我的想法是既然R被推断为Double,为什么不抛出ClassCastException。我怀疑 R 最终被擦除到 Object 但这并没有真正意义,因为如果 R 已经被推断为 Double,为什么 R 会擦除到 Object。既然你和 Wasserman 把事情弄清楚了,我意识到 R 仍然被擦除到 Object 并且在检查它是类型安全之后推理丢失了。
  • 很高兴这有帮助,但请用引发强制转换异常的东西对其进行真正的测试,我现在很好奇,尝试将 Double 更改为像 InputStream 之类的荒谬的东西。
  • 如果我取出它的值并对其进行操作,我只会得到一个 ClassCastException。对不起,我对 Java 还是很陌生,所以我不知道 InputStream 类型是如何工作的。但是,如果我执行System.out.println(d.value/2); 之类的操作,我将得到一个 ClassCastException。只有当我们对其进行操作时,Java 才会意识到它不匹配。我希望我展示了你在寻找什么哈哈哈。

标签: java generics type-erasure


【解决方案1】:

R 类型它会变成Object,即使在方法调用期间推断,这是因为R 没有用,因为你从来没有显式声明它,像这样i.&lt;Double&gt;undo(),在大多数情况下用例,参数类型在方法中用于推断方法参数的类型。关于您的代码流,即使使用 Undone,d.value 也是一个字符串,这是因为 d Undone 类型将被编译为对象,因为 R 类型可以是任何东西,没有如何比较,在编译时,使用您的声明的方法调用的类型推断结果。如果你输入Undone&lt;Double&gt; d = i.&lt;String&gt;undo(),它会抛出一个错误,否则如果你不显式声明,永远不会抛出一个强制转换异常。

【讨论】:

    猜你喜欢
    • 2016-02-14
    • 1970-01-01
    • 2012-04-13
    • 2021-08-04
    • 1970-01-01
    • 2018-07-07
    • 2020-04-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多