【问题标题】:Java - local class and generics, why compiler warning?Java - 本地类和泛型,为什么编译器警告?
【发布时间】:2010-10-20 20:24:29
【问题描述】:

命名local classes 很少使用,通常本地类是匿名的。有人知道为什么下面的代码会产生编译器警告吗?

public class Stuff<E> {
  Iterator<E> foo() {
    class InIterator implements Iterator<E> {
      @Override public boolean hasNext() { return false; }
      @Override public E next() { return null; }
      @Override public void remove() { }
    }
    return new InIterator();
  }
}

警告在new InIterator() 中,上面写着

[unchecked] unchecked conversion
found   : InIterator
required: java.util.Iterator<E>

如果未更改的类被设为匿名,或者如果它成为成员,则警告消失。但是,作为一个命名的本地类,它需要声明 class InIterator&lt;E&gt; implements ... 以使警告消失。

发生了什么事?

【问题讨论】:

  • 只是出于好奇,我的编译器并没有抱怨这个警告......你使用的是什么 JVM?

标签: java generics inner-classes


【解决方案1】:

我相信发生的事情是您通过命名 InIterator 忽略了泛型类型参数,而没有在签名中引用泛型(即使它存在于接口中)。

这属于愚蠢的编译器警告类别:您编写的类使得 100% InIterator 实例将实现 Iterator&lt;E&gt;,但编译器无法识别它。 (我想这取决于编译器。我在 Eclipse 编译器中没有看到警告,但我知道 Eclipse 编译器处理泛型与 JDK 编译器略有不同。)

我认为这不太清楚,也不太接近您的意思,但可能对编译器更友好,最终等效:

public class Stuff<E> {
  Iterator<E> foo() {
    class InIterator<F> implements Iterator<F> {
      @Override public boolean hasNext() { return false; }
      @Override public E next() { return null; }
      @Override public void remove() { }
    }
    return new InIterator<E>();
  }
}

【讨论】:

  • 谢谢大卫。 IntelliJ IDEA 也没有显示任何警告,只是 Sun javac。我知道如何解决这个问题,我只是想知道这种编译器行为是否有一些奇怪但合理的原因,或者它是一个错误。
  • 啊,IDE和javac之间的编译器差异......多么烦人:(
  • 我并不完全清楚 InIterator 不是 Iterator 还是 InIterator 实现了 Iterator 是一个错误。
  • 如果你对编译器的期望很低,这是合理的,这就是我对泛型的看法。如果您希望编译器只在询问“这是否保证是正确的泛型类型?”时才进行快速的逻辑传递。那么这就是你所期望的。如果您希望它回顾得更远一点,那么不,不合法。
  • 嗨 Jorn - 我严重怀疑编译器存在错误。 JLS 似乎没有区分命名和匿名本地类的泛型,因此代码应该编译。为什么添加一个未使用的参数会使警告消失?!比如:public class Stuff { E bar; Iterator foo() { class InIterator 实现 Iterator { ... @Override public E next() { return bar; } ... } 返回新的 InIterator(); } }
【解决方案2】:

嗯,这里没有警告。

import java.util.Iterator;

public class Stuff<E> {
    Iterator<E> foo() {
        class InIterator implements Iterator<E> {
            public boolean hasNext() {
                return false;
            }

            public E next() {
                return null;
            }

            public void remove() {
            }
        }
        return new InIterator();
    }

    public static void main(String[] args) {
        Iterator<String> i = new Stuff<String>().foo();
    }
}

【讨论】:

  • 嗯,你用的是什么编译器?
  • 在 Eclipse (3.4) 以及 Sun JDK 1.5.0.18 和 1.6.0.13 中测试
  • Sun 1.6.0_11 和 1.6.0_12 有警告,我会检查 13,谢谢!
【解决方案3】:

我现在确信这是一个 javac 错误。上面的解决方案向 InIterator 添加了一个隐藏或替换 E 的通用参数并没有帮助,因为它们阻止了迭代器做一些有用的事情,比如返回一个 E 类型的元素 - Stuff 的 E。

但是编译时没有警告(感谢 Jorn 的提示):

public class Stuff<E> {
  E bar;
  Iterator<E> foo() {
    class InIterator<Z> implements Iterator<E> {
      @Override public boolean hasNext() { return false; }
      @Override public E next() { return bar;  }
      @Override public void remove() { }
    }
    return new InIterator<Void>();
  }
}

绝对是一个错误。

【讨论】:

  • 你能提交一个错误并发布链接吗?你让我很好奇。
  • 好吧,根据下面的调整,更新 13 中没有警告。我会检查,但假设他是对的,这意味着它是一个错误 :-)
  • 啊,好的。您是否检查过它是否在某处的错误列表中?
  • 不知道关于tweakt,对我来说1.6.0_13 显示相同的警告。提交错误。
【解决方案4】:

是的,我也同意这应该是一个错误。如果您将本地类从方法中“提升”到成员类中,它也可以正常工作。除了作用域和对局部变量的访问不同之外,两者之间并没有太大区别。

public class Stuff<E> {
  class InIterator implements Iterator<E> {
    @Override public boolean hasNext() { return false; }
    @Override public E next() { return null; }
    @Override public void remove() { }
  }
  Iterator<E> foo() {
    return new InIterator();
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-27
    • 1970-01-01
    相关资源
    最近更新 更多