JavaRush /Java Blog /Random-IT /Classi interne nel metodo locale

Classi interne nel metodo locale

Pubblicato nel gruppo Random-IT
Ciao! Parliamo di un altro tipo di classe nidificata. Vale a dire, sulle classi locali (Metodo classi interne locali). La prima cosa che devi ricordare prima di studiare è la loro posizione nella struttura delle classi nidificate. Classi interne nel metodo locale - 2Sulla base del nostro diagramma, possiamo capire che le classi locali sono un sottotipo delle classi interne, di cui abbiamo parlato in dettaglio in uno dei materiali precedenti . Tuttavia, le classi locali presentano una serie di caratteristiche e differenze importanti rispetto alle classi interne. La chiave è nella loro dichiarazione: una classe locale è dichiarata solo in un blocco di codice. Molto spesso - all'interno di qualche metodo di una classe esterna. Ad esempio, potrebbe assomigliare a questo:
public class PhoneNumberValidator {

   public void validatePhoneNumber(String number) {

        class PhoneNumber {

           private String phoneNumber;

           public PhoneNumber() {
               this.phoneNumber = number;
           }

           public String getPhoneNumber() {
               return phoneNumber;
           }

           public void setPhoneNumber(String phoneNumber) {
               this.phoneNumber = phoneNumber;
           }
       }

       //...code валидации номера
   }
}
IMPORTANTE!Questo codice non verrà compilato una volta incollato in IDEA se hai installato Java 7. Parleremo delle ragioni di ciò alla fine della lezione. In poche parole, il lavoro delle classi locali dipende fortemente dalla versione linguistica. Se questo codice non viene compilato per te, puoi cambiare la versione della lingua in IDEA in Java 8 o aggiungere una parola finalal parametro del metodo in modo che assomigli a questo: validatePhoneNumber(final String number). Dopodiché tutto funzionerà. Questo è un piccolo programma: un validatore di numeri di telefono. Il suo metodo validatePhoneNumber()accetta una stringa come input e determina se si tratta di un numero di telefono. E all'interno di questo metodo abbiamo dichiarato la nostra classe locale PhoneNumber. Potresti avere una domanda logica: perché? Perché dichiarare una classe all'interno di un metodo? Perché non utilizzare una normale classe interna? In effetti si potrebbe fare così: rendere la classe PhoneNumberinterna. Un'altra cosa è che la decisione finale dipende dalla struttura e dallo scopo del tuo programma. Ricordiamo il nostro esempio tratto dalla lezione sulle classi interne:
public class Bicycle {

   private String model;
   private int mawWeight;

   public Bicycle(String model, int mawWeight) {
       this.model = model;
       this.mawWeight = mawWeight;
   }

   public void start() {
       System.out.println("Go!");
   }

   public class HandleBar {

       public void right() {
           System.out.println("Steering wheel to the right!");
       }

       public void left() {

           System.out.println("Steering wheel to the left!");
       }
   }
}
In esso abbiamo realizzato HandleBar(il manubrio) una classe interna della bici. Qual è la differenza? Innanzitutto nell'utilizzo della classe. La classe HandleBardel secondo esempio è un'entità più complessa rispetto PhoneNumberal primo. Innanzitutto, y HandleBarha metodi pubblici righte left(non sono setter e getter). In secondo luogo, non possiamo prevedere in anticipo dove Bicyclepotremmo averne bisogno e la sua classe esterna: possono trattarsi di dozzine di luoghi e metodi diversi, anche all'interno dello stesso programma. Ma con una lezione PhoneNumbertutto è molto più semplice. Il nostro programma è molto semplice. Ha solo una funzione: verificare se il numero è un numero di telefono. Nella maggior parte dei casi il nostro PhoneNumberValidatornon sarà nemmeno un programma indipendente, ma semplicemente una parte della logica di autorizzazione del programma principale. Ad esempio, su vari siti Web, al momento della registrazione, viene spesso richiesto di inserire un numero di telefono. E se digiti delle sciocchezze invece dei numeri, il sito visualizzerà un errore: "Questo non è un numero di telefono!" Per il funzionamento di un sito di questo tipo (o meglio, il meccanismo di autorizzazione dell'utente), i suoi sviluppatori possono includere un nostro analogo nel codice PhoneNumberValidator. In altre parole, abbiamo una classe esterna con un metodo che verrà utilizzato in un punto del programma e da nessun'altra parte. E se lo fa, non cambierà nulla: un metodo fa il suo lavoro, tutto qui. In questo caso, poiché tutta la logica di lavoro è raccolta in un metodo, sarà molto più conveniente e corretto incapsulare lì una classe aggiuntiva. Non ha metodi propri oltre a getter e setter. Essenzialmente abbiamo bisogno solo dei dati del costruttore da esso. Non viene utilizzato in altri metodi. Pertanto, non vi è motivo di estendere le informazioni al riguardo oltre il singolo metodo in cui viene utilizzato. Abbiamo fornito un esempio di dichiarazione di una classe locale in un metodo, ma questa non è l'unica possibilità. Può essere dichiarato semplicemente in un blocco di codice:
public class PhoneNumberValidator {

   {
       class PhoneNumber {

           private String phoneNumber;

           public PhoneNumber(String phoneNumber) {
               this.phoneNumber = phoneNumber;
           }
       }

   }

   public void validatePhoneNumber(String phoneNumber) {


       //...code валидации номера
   }
}
O anche in loop for!
public class PhoneNumberValidator {


   public void validatePhoneNumber(String phoneNumber) {

       for (int i = 0; i < 10; i++) {

           class PhoneNumber {

               private String phoneNumber;

               public PhoneNumber(String phoneNumber) {
                   this.phoneNumber = phoneNumber;
               }
           }

           //...Howая-то логика
       }

       //...code валидации номера
   }
}
Ma questi casi sono estremamente rari. Nella maggior parte dei casi, la dichiarazione avverrà comunque all'interno del metodo. Quindi ci siamo occupati dell'annuncio, abbiamo parlato anche di “filosofia” :) Quali altre caratteristiche e differenze hanno le classi locali rispetto alle classi interne? Non è possibile creare un oggetto di classe locale all'esterno del metodo o del blocco in cui è dichiarato. Immaginiamo di aver bisogno di un metodo generatePhoneNumber()che generi un numero di telefono casuale e restituisca un file PhoneNumber. Non saremo in grado di creare un metodo del genere nella nostra classe di validazione nella situazione attuale:
public class PhoneNumberValidator {

   public void validatePhoneNumber(String number) {

        class PhoneNumber {

           private String phoneNumber;

           public PhoneNumber() {
               this.phoneNumber = number;
           }

           public String getPhoneNumber() {
               return phoneNumber;
           }

           public void setPhoneNumber(String phoneNumber) {
               this.phoneNumber = phoneNumber;
           }
       }

       //...code валидации номера
   }

   //ошибка! компилятор не понимает, что это за класс - PhoneNumber
   public PhoneNumber generatePhoneNumber() {

   }

}
Un'altra caratteristica importante delle classi locali è la possibilità di accedere alle variabili locali e ai parametri del metodo. Nel caso te ne fossi dimenticato, "local" è una variabile dichiarata all'interno di un metodo. String russianCountryCodeCioè, se creiamo una variabile locale all'interno di un metodo per alcuni dei nostri scopi validatePhoneNumber(), possiamo accedervi dalla classe locale PhoneNumber. Tuttavia, ci sono molte sottigliezze che dipendono dalla versione della lingua utilizzata nel programma. All'inizio della lezione, abbiamo notato che il codice in uno degli esempi potrebbe non essere compilabile in Java 7, ricordate? Ora diamo un'occhiata alle ragioni di ciò :) In Java 7, una classe locale può accedere a una variabile locale o a un parametro del metodo solo se sono dichiarati nel metodo come final:
public void validatePhoneNumber(String number) {

   String russianCountryCode = "+7";

   class PhoneNumber {

       private String phoneNumber;

       //ошибка! параметр метода должен быть объявлен How final!
       public PhoneNumber() {
           this.phoneNumber = number;
       }

       public void printRussianCountryCode() {

           //ошибка! локальная переменная должна быть объявлена How final!
           System.out.println(russianCountryCode);
       }

   }

   //...code валидации номера
}
Qui il compilatore ha generato due errori. Ma qui è tutto in ordine:
public void validatePhoneNumber(final String number) {

   final String russianCountryCode = "+7";

    class PhoneNumber {

       private String phoneNumber;


       public PhoneNumber() {
           this.phoneNumber = number;
       }

       public void printRussianCountryCode() {

           System.out.println(russianCountryCode);
       }

    }

   //...code валидации номера
}
Ora conosci il motivo per cui il codice all'inizio della lezione non è stato compilato: una classe locale in Java 7 ha accesso solo ai finalparametri -method e finalalle variabili -local. In Java 8, il comportamento delle classi locali è cambiato. In questa versione del linguaggio, la classe locale ha accesso non solo alle finalvariabili e ai parametri -local, ma anche a effective-final. Effective-finalè una variabile il cui valore non è cambiato dall'inizializzazione. Ad esempio, in Java 8 possiamo facilmente visualizzare una variabile sulla console russianCountryCode, anche se non lo è final. La cosa principale è che non cambia il suo significato. In questo esempio, tutto funziona come dovrebbe:
public void validatePhoneNumber(String number) {

  String russianCountryCode = "+7";

    class PhoneNumber {

       public void printRussianCountryCode() {

           //в Java 7 здесь была бы ошибка
           System.out.println(russianCountryCode);
       }

    }

   //...code валидации номера
}
Ma se modifichiamo il valore della variabile subito dopo l'inizializzazione, il codice non verrà compilato.
public void validatePhoneNumber(String number) {

  String russianCountryCode = "+7";
  russianCountryCode = "+8";

    class PhoneNumber {

       public void printRussianCountryCode() {

           //error!
           System.out.println(russianCountryCode);
       }

    }

   //...code валидации номера
}
Ma non per niente una classe locale è un sottotipo di una classe interna! Hanno anche punti comuni. Una classe locale ha accesso a tutti i campi e metodi (anche privati) della classe esterna: sia statici che non statici. Ad esempio, aggiungiamo un campo statico alla nostra classe di validazione String phoneNumberRegex:
public class PhoneNumberValidator {

   private static String phoneNumberRegex = "[^0-9]";

   public void validatePhoneNumber(String phoneNumber) {
       class PhoneNumber {

           //......
       }
   }
}
La convalida verrà eseguita utilizzando questa variabile statica. Il metodo controlla se la stringa che gli viene passata contiene caratteri che non corrispondono all'espressione regolare " [^0-9]" (ovvero, il carattere non è un numero da 0 a 9). Possiamo facilmente accedere a questa variabile dalla classe locale PhoneNumber. Ad esempio, scrivi un getter:
public String getPhoneNumberRegex() {

   return phoneNumberRegex;
}
Le classi locali sono simili alle classi interne perché non possono definire o dichiarare alcun membro statico. Le classi locali nei metodi statici possono fare riferimento solo a membri statici della classe che li racchiude. Ad esempio, se non si definisce una variabile (campo) della classe che la racchiude come statica, il compilatore Java genera un errore: "Non è possibile fare riferimento a una variabile non statica da un contesto statico". Le classi locali non sono statiche perché hanno accesso ai membri dell'istanza del blocco contenitore. Pertanto, non possono contenere la maggior parte dei tipi di dichiarazioni statiche. Non è possibile dichiarare un'interfaccia all'interno di un blocco; Le interfacce sono di natura statica. Questo codice non verrà compilato:
public class PhoneNumberValidator {
   public static void validatePhoneNumber(String number) {
       interface I {}

       class PhoneNumber implements I{
           private String phoneNumber;

           public PhoneNumber() {
               this.phoneNumber = number;
           }
       }

       //...code валидации номера
   }
}
Ma se un'interfaccia viene dichiarata all'interno di una classe esterna, la classe PhoneNumberpuò implementarla:
public class PhoneNumberValidator {
   interface I {}

   public static void validatePhoneNumber(String number) {

       class PhoneNumber implements I{
           private String phoneNumber;

           public PhoneNumber() {
               this.phoneNumber = number;
           }
       }

       //...code валидации номера
   }
}
Le classi locali non possono dichiarare inizializzatori statici (blocchi di inizializzazione) o interfacce. Ma le classi locali possono avere membri statici, purché siano variabili costanti ( static final). Ecco cosa sono, lezioni locali! Come puoi vedere, presentano molte differenze rispetto alle classi interne. Abbiamo dovuto approfondire anche le funzionalità della versione linguistica per capire come funzionano :) Nella prossima lezione parleremo delle classi interne anonime, l'ultimo gruppo di classi nidificate. Buona fortuna con i tuoi studi! :)
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION