il modificatore 'static' è consentito solo in dichiarazioni variabili costanti; PERCHÉ?

3

Ancora e ancora mi trovo in situazioni in cui voglio fare questo:

class Outer
{
    private static final Runnable Inner = new Runnable() 
    {
        private static final String CONSTANT1 = "foo";
        private static final int CONSTANT2 = CONSTANT1.length(); //'static' gives error
        private static final int CONSTANT3 = f(); //'static' gives error

        private static int f() //'static' gives error
        {
            return CONSTANT1.length();
        }

        @Override public void run() {}
    };

    private static final String CONSTANT1 = "foo";
    private static final int CONSTANT2 = CONSTANT1.length(); //this is fine!
    private static final int CONSTANT3 = f(); //this is fine!

    private static int f() //this is fine!
    {
        return CONSTANT1.length();
    }
}

Nell'editor dell'IDE (IntelliJ IDEA) l'errore legge "Le classi interne non possono avere dichiarazioni statiche", che è fuorviante, perché se fosse così, allora CONSTANT1 avrebbe anche un errore, ma non .

Al di fuori dell'editor, il compilatore riporta l'errore come segue: java: Illegal static declaration in inner class <anonymous bla bla bla> modifier 'static' is only allowed in constant variable declarations .

Quindi qualcuno conosce le ragioni tecniche alla base di questa limitazione imposta dal compilatore java? Perché il modificatore 'statico' è consentito solo nelle dichiarazioni di variabili costanti in istanze di classi anonime? Qual è la difficoltà nel consentire "statico" in questi casi?

    
posta Mike Nakis 26.09.2016 - 10:31
fonte

1 risposta

3

Java cerca di comportarsi in modo ragionevole, ma poiché è un linguaggio piuttosto complesso, a volte fallisce. Hai trovato un caso limite interessante in cui una guardia contro un comportamento non valido crea un falso negativo.

Di solito, i campi static possono essere inizializzati con espressioni arbitrarie, purché non facciano riferimento alle variabili di istanza.

Le classi interne appartengono a un'istanza della classe esterna, non alla classe esterna stessa. Mentre le classi interne sono logicamente distinte, condividono la stessa classe fisica. Ciò significa che i campi static sono condivisi tra tutte le classi interne. Questo interrompe la separazione logica, a meno che i campi static sono costanti (vedi JLS §8.1.3) e non possono essere mutati, cioè: non possono essere riassegnati e non possono cambiare il loro valore. Credo che questa restrizione sia ragionevole, data l'implementazione delle classi interne.

La riassegnazione può essere prevenuta con final , ma Java non ha alcun meccanismo per tracciare le operazioni mutanti e non mutanti. C ++ ha un tale meccanismo e può marcare metodi come const e anche constexpr per operazioni computabili in fase di compilazione. Tutto ciò che Java ha è un concetto di espressioni costanti (JLS §15.28) : fondamentalmente solo letterali e aritmetici.

Quindi una classe interna può contenere la costante static final String CONSTANT1 = "foo" . Tuttavia, CONSTANT1.length() non è un'espressione costante perché stai invocando un metodo. In pratica questo non dovrebbe essere un problema perché la classe String è immutabile, ma il JLS non fa caso speciale alla classe String . Allo stesso modo, f() non è un'espressione costante.

Ora la cosa veramente triste è che la tua classe interna new Runnable() { ... } viene creata in un contesto statico, quindi il problema della classe interna logicamente separato non esiste. Sarebbe ragionevolmente possibile che le classi anonime in un contesto statico vengano dichiarate static , poiché le classi interne static non hanno nessuna delle restrizioni delle classi interne. Tuttavia, il JLS richiede che le classi anonime non siano mai statiche ( JLS §15.9.5 ).

Quindi un sistema complesso come Java ha delle leggere incongruenze, che è fastidioso ma non sorprendente. Questa incoerenza potrebbe essere risolta eseguendo il monitoraggio delle operazioni costanti per tutti i metodi (che sarebbe un enorme cambiamento nella lingua) o rimuovendo classi interne non statiche, che IMHO sarebbe stato ragionevole perché è banale implementarle da soli. Tuttavia, quello non è il Java che abbiamo.

    
risposta data 26.09.2016 - 12:30
fonte

Leggi altre domande sui tag