Domanda

classi locali sono molto raramente utilizzati, di solito le classi locali sono anonimi. Qualcuno sa il motivo per cui il codice di seguito genera un avviso del compilatore?

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

L'avviso è in new InIterator() e dice

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

Se la classe, invariata, è in forma anonima, o se si è fatto un membro, l'avviso va via. Tuttavia, come classe locale di nome, richiede un class InIterator<E> implements ... dichiarazione per l'avvertimento di andare via.

Che cosa sta succedendo?

È stato utile?

Soluzione 3

Sono ormai convinto che si tratta di un bug javac. Le soluzioni di cui sopra che aggiungono un parametro generico per InIterator che o si nasconde o sostituisce E non sono utili, perché si oppongono alla iteratore di fare qualcosa di utile, come la restituzione di un elemento di tipo E -. E Stuff

Tuttavia, questo viene compilato senza avvisi (grazie Jorn per il suggerimento):

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

Sicuramente un bug.

Altri suggerimenti

Credo che quello che sta succedendo è che si sta ignorando l'argomento di tipo generico nominando InIterator senza un riferimento al generico nella firma (anche se è presente nell'interfaccia).

Questo rientra nella categoria di avvisi del compilatore sciocche: hai scritto la classe in modo che il 100% dei casi InIterator attueranno Iterator<E>, ma il compilatore non lo riconosce. (Suppongo che questo dipende dal compilatore. Non vedo l'avvertimento nel mio compilatore Eclipse, ma so che il compilatore Eclipse gestisce farmaci generici in modo leggermente diverso rispetto al compilatore JDK.)

Io sostengo che questo è meno chiaro, e meno vicino a quello che vuoi dire, ma forse più compilatore amichevole, e, infine, equivalente:

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

Hmm, nessun avviso qui.

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

Sì, sono anche d'accordo che questo dovrebbe essere un bug. Se "sollevare" la classe locale fuori del metodo in una classe membro, funziona benissimo anche. E non c'è molta differenza tra i due, tranne diversa scoping e l'accesso alle variabili locali.

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();
  }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top