Visualizzazione dei risultati da 1 a 4 su 4
  1. #1

    Inizializzare variabili di classi dichiarate in altre classi

    Ciao ragazzi, è da qualche giorno che mi sto barcamenando per capire come assegnare dei valori a delle variabili appartenenti a delle classi che sono dichiarate in un'altra classe. Esempio:


    codice:
    public class ProvaClasse{
    
    class Punto{
          int x;
          int y;
    }
    
    class Rettangolo{
          int altezza; 
          int base;
          Punto posizione;
    }
    
    public static void main(String[]args){
          
          Posizione p= new Posizione();
          p.x= 3;
          p.y= 5;
    
          Rettangolo rett= new Rettangolo();
          rett.posizione.x= 5;
          System.out.println(rett.posizione.x);
          rett.posizione.y= 9;
          System.out.println(rett.posizione.y);
    }
    }
    In questo modo non lo dà per giusto, perché dice "NullPointerException:attempt to write to field 'int java".
    Mentre assegnando l'istanza "p" a rett.posizione stampa correttamente i valori p.x e p.y:

    codice:
    public static void main(String[]args){
          
          Posizione p= new Posizione();
          p.x= 3;
          p.y= 5;
    
          Rettangolo rett= new Rettangolo();
          rett.posizione= p;
          System.out.println(rett.posizione.x);
          System.out.println(rett.posizione.y);
    }
    Per assegnare i valori bisogna sempre creare un'istanza di tutte le classi usate o c'è un altro metodo per controllare le variabili "x" e "y" direttamente dalla classe "Rettangolo" che contiene la classe "Punto"?

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Innanzitutto cosa è "Posizione"? (intendo quel new Posizione() nel main). È un'altra classe (che non si vede) o hai solo sbagliato a scrivere invece di Punto?

    Comunque tieni presente una cosa importante: le classi Punto e Rettangolo tecnicamente sono delle "inner class" (poiché sono definite dentro ProvaClasse e non con static). Una inner class è molto particolare ed ha regole specifiche. Se non sai bene cosa sono e cosa comportano, il semplice consiglio è di evitarle.

    Ora, ignorando un momento i buoni principi della programmazione ad oggetti (incapsulamento, mantenere privati i campi, ecc...), volendo accedere direttamente ai campi, quello che segue è tecnicamente corretto.

    codice:
    public class Prova {
        public static void main(String[] args) {
            Rettangolo rett = new Rettangolo();
            rett.altezza = 50;
            rett.base = 80;
            rett.posizione = new Punto();
            // ora posso accedere a x/y poiché Punto è istanziato!
            rett.posizione.x = 10;
            rett.posizione.y = 30;
    
            System.out.println("x , y = " + rett.posizione.x + " , " + rett.posizione.y);
            System.out.println("base x altezza = " + rett.base + " x " + rett.altezza);
        }
    }
    
    // Punto e Rettangolo sono FUORI da Prova
    
    class Punto {
        public int x;
        public int y;
    }
    
    class Rettangolo {
        public int altezza;
        public int base;
        public Punto posizione;
    }
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  3. #3
    Si mi ero sbagliato con il nome della classe "Posizione" invece di "Punto" dato che non lo avevo sotto mano il programma che avevo scritto. Ma a quale fine mantenere i campi privati e usare l'incapsulamento? Per una questione di prassi usuale e di ordine? E dichiarare le variabili private per non renderle accessibili dall'esterno?
    Comunque è come dico io quindi, bisogna istanziare le classi per poter accedere agli elementi. Conviene quindi istanziare la classe direttamente nel punto in cui si dichiara? Esempio:



    codice:
    public class ProvaClasse {
    
    
        public static void main(String[] args) {
            Rettangolo rett = new Rettangolo();
            rett.altezza = 50;
            rett.base = 80;
    
    
            rett.posizione.x = 10;
            rett.posizione.y = 30;
    
    
            System.out.println(rett.posizione.x);
            System.out.println(rett.posizione.y);
        }
    }
    
    
    class Punto {
        int x;
        int y;
    }
    
    
    class Rettangolo {
        int altezza;
        int base;
        Punto posizione= new Punto();
    In questo caso anche senza "public" funziona.
    Questo programma è comunque un esempio. Ma perché evitare le classe interne o inner class? Quali sono i lati negativi?
    Ultima modifica di Pierfrank; 14-07-2016 a 14:47

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da Pierfrank Visualizza il messaggio
    Ma a quale fine mantenere i campi privati e usare l'incapsulamento? Per una questione di prassi usuale e di ordine?
    Ci sono svariati motivi, tecnici e concettuali.

    1) L'incapsulamento rientra in tutto un discorso più grande sul "information hiding", ovvero sul fatto di nascondere informazioni, dettagli interni, che non devono ("non dovrebbero") interessare a chi sta semplicemente usando una certa funzionalità esposta da una classe o altro.
    Se una classe Persona ha un campo annoNascita (short), è importante che tu debba saperlo e poterci accedere direttamente? Generalmente no. Se ci puoi accedere direttamente, chi ha sviluppato quella classe (che potresti non essere tu), non potrebbe mai più cambiare il campo in es. un int o con un nuovo nome annoDiNascita. Se lo fa ... altro codice esterno si "spacca" e dovrebbe essere rimaneggiato e ricompilato.
    Insomma, mantenere "nascosti" dettagli interni permette, tra le altre cose, di facilitare la evoluzione della classe, perlomeno di quella parte nascosta.

    2) Se si permette l'accesso diretto ad un campo non si possono imporre "vincoli" sul valore (si chiamano "invarianti"). Le istruzioni di accesso al campo sarebbero sparpagliate ovunque venga usato quel campo e chi ha scritto la classe non ne avrebbe il controllo.
    E se volessi fare in modo che il campo annoNascita NON possa essere mai minore di 1900? Lo puoi fare solo con l'incapsulamento, ovvero mettendo il campo private e offrendo i metodi "accessori" getter/setter public.

    codice:
    public class Persona {
        private int annoNascita;
    
        public void setAnnoNascita(int annoNascita) {
            if (annoNascita < 1900) {
                throw new IllegalArgumentException("annoNascita non può essere minore di 1900");
            }
    
            this.annoNascita = annoNascita;
        }
    
        public int getAnnoNascita() {
            return annoNascita;
        }
    }

    Così l'invariante "l'anno di nascita deve sempre essere maggiore/uguale a 1900" è sempre garantito. Dimentichiamo un momento un uso "malizioso" della reflection, per cui sarebbe possibile accedere al campo anche se private. Ma in tutti gli altri usi normali, non c'è modo di sovvertire questo vincolo.

    Senza incapsulamento, ovvero rendendo il campo accessibile, questo vincolo NON sarebbe possibile.


    Quote Originariamente inviata da Pierfrank Visualizza il messaggio
    Comunque è come dico io quindi, bisogna istanziare le classi per poter accedere agli elementi.
    Ovviamente, se non hai un oggetto ..... non vedo cosa puoi settarci.

    Quote Originariamente inviata da Pierfrank Visualizza il messaggio
    Conviene quindi istanziare la classe direttamente nel punto in cui si dichiara?
    Dipende dal design e da chi si vuole che sia il "proprietario" dell'oggetto e del suo ciclo di vita.

    Il tuo esempio è tecnicamente corretto.

    Quote Originariamente inviata da Pierfrank Visualizza il messaggio
    In questo caso anche senza "public" funziona.
    Nei miei/tuoi esempi, public o non public cambia poco. Se non si specifica un modificatore di accesso (public/protected/private) il livello di accesso per i membri delle classi è quello di "default", cioè package-level. Siccome le classi sono nello stesso package, funziona sia public-level che package-level. Tecnicamente anche protected, se si vuole.

    Quote Originariamente inviata da Pierfrank Visualizza il messaggio
    Ma perché evitare le classe interne o inner class? Quali sono i lati negativi?
    Come avevi prima Punto/Rettangolo come "inner class", un limite è che nel main NON potevi fare banalmente

    Rettangolo rett= new Rettangolo();

    Quel tuo codice iniziale non può compilare. E c'è un motivo: una inner class è particolare perché ha una relazione molto speciale con la classe "contenitore". Nel senso che una istanza della inner class deve essere associata ad una specifica istanza della classe contenitore. E nel tuo codice non avevi neanche una istanza di ProvaClasse.

    Se ti interessa e continuerai lo studio di Java (ne hai tanto .. molto davanti ....) lo scoprirai. Ma per il momento il consiglio semplice è: ignora inner/nested class e non dichiarare mai classi (tipi in generale) dentro altri tipi. Fino a quando non arriverai all'argomento.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.