Domanda

Stavo guardando il codice Java per LinkedList e ho notato che utilizzava una classe nidificata statica, Entry .

public class LinkedList<E> ... {
...

 private static class Entry<E> { ... }

}

Qual è la ragione per usare una classe annidata statica, piuttosto che una normale classe interna?

L'unica ragione a cui ho potuto pensare è che Entry non ha accesso alle variabili di istanza, quindi dal punto di vista OOP ha un migliore incapsulamento.

Ma ho pensato che potrebbero esserci altri motivi, forse le prestazioni. Cosa potrebbe essere?

Nota. Spero di aver corretto i miei termini, l'avrei definita una classe interna statica, ma penso che sia sbagliato: http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html

È stato utile?

Soluzione

La pagina Sun a cui ti colleghi presenta alcune differenze chiave tra i due:

  

Una classe nidificata è un membro della sua classe che la racchiude. Le classi nidificate non statiche (classi interne) hanno accesso ad altri membri della classe che la racchiude, anche se sono dichiarate private. Le classi nidificate statiche non hanno accesso ad altri membri della classe che la racchiude.
  ...

     

Nota: una classe nidificata statica interagisce con i membri dell'istanza della sua classe esterna (e altre classi) proprio come qualsiasi altra classe di livello superiore. In effetti, una classe nidificata statica è comportamentalmente una classe di livello superiore che è stata nidificata in un'altra classe di livello superiore per comodità di imballaggio.

Non è necessario che LinkedList.Entry sia la classe di primo livello in quanto è solo utilizzato da LinkedList (ce ne sono altri interfacce che hanno anche classi nidificate statiche denominate Entry , come Map.Entry - stesso concetto). E poiché non ha bisogno di accedere ai membri di LinkedList, ha senso che sia statico: è un approccio molto più pulito.

Come Jon Skeet sottolinea , penso che sia un'idea migliore se stai usando una classe nidificata è iniziare con il fatto che sia statico, quindi decidi se deve davvero essere non statico in base al tuo utilizzo.

Altri suggerimenti

A mio avviso, la domanda dovrebbe essere al contrario ogni volta che vedi una classe interiore - davvero deve essere una classe interiore, con la complessità e l'implicito extra (piuttosto che riferimento esplicito e più chiaro, IMO) a un'istanza della classe contenente?

Intendiamoci, sono di parte come fan di C # - C # non ha l'equivalente di classi interne, sebbene abbia tipi nidificati. Non posso dire di aver perso ancora le lezioni interne :)

Ci sono problemi di conservazione della memoria non ovvi da prendere in considerazione qui. Poiché una classe interna non statica mantiene un riferimento implicito alla sua classe "esterna", se un'istanza della classe interna è fortemente referenziata, anche l'istanza esterna è fortemente referenziata. Questo può portare a qualche grattacapo quando la classe esterna non viene raccolta spazzatura, anche se sembra che nulla fa riferimento a essa.

Bene, per prima cosa, le classi interne non statiche hanno un campo nascosto aggiuntivo che punta all'istanza della classe esterna. Quindi se la classe Entry non fosse statica, quindi oltre ad avere accesso di cui non ha bisogno, porterebbe circa quattro puntatori anziché tre.

Di norma, direi, se definisci una classe che è praticamente lì per fungere da raccolta di membri di dati, come una "struttura" in C, considera di renderlo statico.

la classe nidificata statica è come qualsiasi altra classe esterna, in quanto non ha accesso ai membri della classe esterna.

Solo per comodità di packaging possiamo raggruppare le classi nidificate statiche in una classe esterna a fini di leggibilità. A parte questo, non esiste altro caso d'uso di classe nidificata statica.

Esempio per questo tipo di utilizzo, puoi trovarlo nel file Android R.java (risorse). La cartella Res di Android contiene layout (contenenti disegni dello schermo), cartella disegnabile (contenente immagini utilizzate per il progetto), cartella valori (che contiene costanti di stringa), ecc.

Sine tutte le cartelle fanno parte della cartella Res, lo strumento Android genera un file R.java (risorse) che contiene internamente molte classi nidificate statiche per ciascuna delle loro cartelle interne.

Ecco l'aspetto del file R.java generato in Android: Qui stanno usando solo per comodità di imballaggio.

/* AUTO-GENERATED FILE.  DO NOT MODIFY.
 *
 * This class was automatically generated by the
 * aapt tool from the resource data it found.  It
 * should not be modified by hand.
 */

package com.techpalle.b17_testthird;

public final class R {
    public static final class drawable {
        public static final int ic_launcher=0x7f020000;
    }
    public static final class layout {
        public static final int activity_main=0x7f030000;
    }
    public static final class menu {
        public static final int main=0x7f070000;
    }
    public static final class string {
        public static final int action_settings=0x7f050001;
        public static final int app_name=0x7f050000;
        public static final int hello_world=0x7f050002;
    }
}

La classe interna statica viene utilizzata nel modello del builder. La classe interna statica può creare un'istanza della sua classe esterna che ha solo un costruttore privato. Quindi puoi usare la classe interna statica per creare un'istanza della classe esterna che ha solo un costruttore privato. Non puoi fare lo stesso con la classe interna poiché devi creare l'oggetto della classe esterna prima di accedere alla classe interna.

class OuterClass {
    private OuterClass(int x) {
        System.out.println("x: " + x);
    }

    static class InnerClass {
        public static void test() {
            OuterClass outer = new OuterClass(1);
        }
    }
}

public class Test {
    public static void main(String[] args) {
        OuterClass.InnerClass.test();
        // OuterClass outer = new OuterClass(1); // It is not possible to create outer instance from outside.
    }
}

Questo produrrà x: 1

Da http://docs.oracle.com/javase/tutorial /java/javaOO/whentouse.html :

  

Utilizzare una classe nidificata (o interna) non statica se è necessario l'accesso   ai campi e ai metodi non pubblici di un'istanza che lo racchiude. Usa una statica   classe nidificata se non si richiede questo accesso.

Esempio semplice:

package test;

public class UpperClass {
public static class StaticInnerClass {}

public class InnerClass {}

public static void main(String[] args) {
    // works
    StaticInnerClass stat = new StaticInnerClass();
    // doesn't compile
    InnerClass inner = new InnerClass();
}
}

Se non statica la classe non può essere istanziata se non in un'istanza della classe superiore (quindi non nell'esempio in cui main è una funzione statica)

Uno dei motivi per statico vs. normale ha a che fare con il caricamento di classe. Non puoi creare un'istanza di una classe interna nel costruttore del suo genitore.

PS: ho sempre capito che "nidificato" e "interno" sono intercambiabili. Potrebbero esserci sottili sfumature nei termini, ma la maggior parte degli sviluppatori Java potrebbe capire.

Le classi interne non statiche possono causare perdite di memoria mentre le classi interne statiche proteggono da esse. Se la classe esterna contiene dati considerevoli, può ridurre le prestazioni dell'applicazione.

Non conosco la differenza di prestazioni, ma come dici tu, la classe nidificata statica non fa parte di un'istanza della classe acclusa. Sembra solo più semplice creare una classe nidificata statica a meno che non sia davvero necessario che sia una classe interna.

È un po 'come il motivo per cui ho sempre reso definitive le mie variabili in Java - se non sono definitive, so che c'è qualcosa di divertente in esse. Se usi una classe interna anziché una classe nidificata statica, dovrebbe esserci una buona ragione.

L'uso di una classe nidificata statica anziché non statica può in alcuni casi risparmiare spazio. Ad esempio: implementare un Comparator all'interno di una classe, ad esempio Studente.

public class Student {
  public static final Comparator<Student> BY_NAME = new ByName();
  private final String name;
  ...
  private static class ByName implements Comparator<Student> {
    public int compare() {...}
  }
}

Quindi il statico assicura che la classe Student abbia un solo Comparatore, anziché istanziarne uno nuovo ogni volta che viene creata una nuova istanza studentesca.

Adavantage of inner class--

  1. uso singolo
  2. supporta e migliora l'incapsulamento
  3. leggibilità
  4. accesso al campo privato

Senza esistere della classe esterna la classe interna non esisterà.

class car{
    class wheel{

    }
}

Esistono quattro tipi di classe interna.

  1. classe interna normale
  2. Metodo Classe interna locale
  3. Classe interna anonima
  4. classe interna statica

punto ---

  1. dalla classe interna statica, possiamo accedere solo al membro statico della classe esterna.
  2. All'interno della classe interna non possiamo dichiarare membro statico.
  3. inorder per invocare la normale classe interna nell'area statica della classe esterna.

    Outer 0 = new Outer (); Outer.Inner i = O.new Inner ();

  4. inorder per invocare la normale classe interna nell'area di istanza della classe esterna.

    Inner i = new Inner ();

  5. inorder per invocare la normale classe interna al di fuori della classe esterna.

    Outer 0 = new Outer (); Outer.Inner i = O.new Inner ();

  6. all'interno della classe interna Questo puntatore alla classe interna.

    this.member-current classe interna outerclassname.this - classe esterna

  7. per il modificatore applicabile della classe interna è - pubblico, predefinito,

    , astratto, strictf, +, protetto, static privato finale

  8. outer $ inner è il nome del nome della classe interna.

  9. classe interna all'interno del metodo dell'istanza, quindi possiamo accedere al campo statico e di istanza della classe esterna.

classe 10.inner all'interno del metodo statico, quindi possiamo accedere solo al campo statico di

classe esterna.

class outer{

    int x=10;
    static int y-20;

    public void m1() {
        int i=30;
        final j=40;

        class inner{

            public void m2() {
                // have accees x,y and j
            }
        }
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top