Java - local class and generics, why compiler warning?

时间秒杀一切 提交于 2019-12-22 07:41:01

问题


Named local classes are very rarely used, usually local classes are anonymous. Does anybody know why the code below generates a compiler warning?

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

The warning is in new InIterator() and it says

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

If the class, unchanged, is made anonymous, or if it is made a member, the warning goes away. However, as a named local class, it requires a declaration class InIterator<E> implements ... for the warning to go away.

What's going on?


回答1:


I believe what's happening is you are ignoring the generic type argument by naming InIterator without a reference to the generic in the signature (even though it is present in the interface).

This falls into the category of silly compiler warnings: you've written the class so that 100% InIterator instances will implement Iterator<E>, but the compiler doesn't recognize it. (I suppose this depends on the compiler. I don't see the warning in my Eclipse compiler, but I know that the Eclipse compiler handles generics slightly differently than the JDK compiler.)

I argue that this is less clear, and less close to what you mean, but perhaps more compiler friendly, and ultimately equivalent:

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



回答2:


Hmm, no warnings here.

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



回答3:


I am now convinced that it's a javac bug. The solutions above that add a generic parameter to InIterator that either hides or replaces E aren't helpful, because they preclude the iterator from doing something useful, like returning an element of type E - Stuff's E.

However this compiles with no warnings (thanks Jorn for the hint):

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

Definitely a bug.




回答4:


Yeah, I also agree that this should be a bug. If you "lift" the local class out of the method into a member class, it works fine too. And there isn't much difference between the two except different scoping and access to local variables.

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


来源:https://stackoverflow.com/questions/772914/java-local-class-and-generics-why-compiler-warning

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!