有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

编译器构造为什么这是无效的Java?三值运算符输出类型

看看这个代码

// Print object and recurse if iterable
private static void deep_print(Object o) {
  System.out.println(o.getClass().toString() + ", " + o.toString());

  boolean iter = false;
  Iterable<?> i1 = null;
  Object[] i2 = null;

  if (o instanceof Iterable<?>) {
    iter = true;
    i1 = (Iterable<?>) o;
  } else if (o instanceof Object[]) {
    iter = true;
    i2 = (Object[]) o;
  }

  if (iter) {
    for (Object o_ : i2 == null ? i1 : i2) deep_print(o_); // ERROR: Can only iterate over an array or an instance of java.lang.Iterable
  }

我知道怎么解决。我只是想知道为什么会这样。编译器不应该简单地检查所有可能的输出吗


共 (2) 个答案

  1. # 1 楼答案

    在这种情况下,条件表达式具有两种类型中最小上界的类型,即Object,而foreach循环不适用于Object

  2. # 2 楼答案

    表达式(i2 == null) ? i1 : i2的静态结果类型是对象i1i2的共同祖先。for语句要求表达式的静态类型Iterable或数组类型。事实并非如此,因此会出现编译错误

    现在,如果你问为什么编译器不推断(i2 == null) ? i1 : i2总是一个数组或一个Iterable:

    1. Java语言规范(JLS)不允许这样做
    2. 如果JLS确实允许(但不要求),那么不同的编译器的行为会有所不同,这取决于它们在定理证明方面的表现。糟糕
    3. 如果JLS需要它,那么编译器必须包含一个复杂的定理证明程序`1(糟糕-缓慢),并且您会遇到解决停止问题2(糟糕-糟糕)的“小麻烦”
    4. 实际上,编译器需要知道表达式的两种类型中的哪一种,因为它需要在每种情况下生成不同的代码

    假设,如果Java类型的系统有点不同,那么这个特殊的情况可以得到更好的处理。具体来说,如果Java支持algebraic data types,那么可以将o声明为“对象数组或iterable”。。。而且for循环是可检查类型的


    1-假设o已初始化为o = (x * x < 0) ? new Object() : new Object[0]。要确定这总是会导致Object[]实例,需要一个小证明,证明(实数)的平方不是负的。这是一个简单的例子,可以构造任意复杂的例子,需要任意困难的证明

    2-数学证明停顿问题是一个不可数函数。换句话说,存在数学上无法证明它们是否终止的函数