Угњеждене класе

Већ смо се упознали са дефиницијом класе и шта она представља. До сада смо дефинисали класе које су одвојене у свом изворном фајлу, међутим, могуће је дефинисање класа унутар дефиниције неке друге класе. Тако дефинисане класе се називају угњеждене класе.

Ovo je Java Applet napravljen u GeoGebri sa www.geogebra.org - izgleda da nemate instaliranu Javu; molim otvorite www.java.com
Анимација 9.9. Пример класе Pristaniste која у себи има угњеждену класу Brod

*У случају да се анимација не приказује, притиснути дугме Прикажи слику




Уколико нам је потребно, могуће је и дефинисање угњеждене класе унутар угњеждене класе.

Ovo je Java Applet napravljen u GeoGebri sa www.geogebra.org - izgleda da nemate instaliranu Javu; molim otvorite www.java.com
Анимација 9.10. Пример класе Pristaniste која у себи има угњеждену класу Brod, док класа Brod има угњеждену класу Sidro

*У случају да се анимација не приказује, притиснути дугме Прикажи слику




Дефиниција угњеждене класе:

public class Pristaniste
{
    //Promenljiva klase Pristaniste kojom je definisana drzava u kojoj se nalazi pristaniste
    public string drzava = "Srbija";
    //Promenljiva klase Pristaniste kojom je definisan naziv pristanista
    public string naziv = "Savsko";
	
    public class Brod
    {
        //Promenljiva klase Brod kojom je definisana sirina broda
        public int sirina = 5;
        //Promenljiva klase Brod kojom je definisana visina broda
        public int visina = 5;
        //Promenljiva klase Brod kojom je definisana duzina broda
        public int duzina = 15;
		
        public class Sidro
        {
            //Promenljiva klase Sidro kojom je definisana tezina sidra
            public int tezina = 10;
            
        }
    }
}

Објекат

Уколико желимо да у спољашњој класи користимо чланове угњеждене класе, потребно је најпре да у спољашњој класи креирамо објекат угњеждене класе. То можемо учинити на следећи начин:


public class Pristaniste
{
    //Kreiranje objekta klase Brod
    Brod ug = new Brod();
    //Promenljiva klase Pristaniste kojom je definisana drzava u kojoj se nalazi pristanista
    public string drzava = "Srbija";
    //Promenljiva klase Pristaniste kojom je definisan naziv pristanista
    public string naziv = "Savsko";
	
    //Ostali clanovi klase Pristaniste
	
    public class Brod
    {
        //Kreiranje objekta klase Sidro	
        Sidro ug1 = new Sidro();
        
        //Promenljiva klase Brod kojom je definisana sirina broda
        public int sirina = 5;
        //Promenljiva klase Brod kojom je definisana visina broda
        public int visina = 5;
        //Promenljiva klase Brod kojom je definisana duzina broda
        public int duzina = 15;
		
        //Ostali clanovi klase Brod
		
        public class Sidro
        {
            
            //Promenljiva klase Sidro kojom je definisana tezina sidra
            public int tezina = 10;
			
            //Ostali clanovi klase Sidro
        }
    }
} 
Након ове наредбе у класи Pristaniste није креиран ни један објекат класе Sidro. Ако желимо да креирамо објекат класе Sidro потребно је да након наредбе
Brod ug = new Brod();
додамо
Brod.Sidro ug1 = new Brod.Sidro();
Сада смо креирали и објекат класе Sidro, и можемо да користимо њене чланове.
Уколико не ставимо да је наша угњеждена класа јавна, тј. public, нећемо моћи ни да је користимо изван класе у коју је угњеждена.
Члановима класе Brod приступамо навођењем имена креираног објекта, затим следи тачка па назив члана којем приступамо, у овом случају то би изгледало овако:
ug.sirina;
и слично за класу Sidro
ug1.tezina;

Конструктор

Да би смо креирали објекат потребан нам је и конструктор. Увек када креирамо објекат неке класе позива се специјална врста метода, тзв. конструктор. У претходним примерима сте вероватно приметили да такав метод нисмо дефинисали, а ипак смо креирали објекте угњеждених класа. Зашто је то тако?
Уколико се деси да сами не дефинишете конструктор класе, приликом покретања програма компајлер обезбеђује подразумевани конструктор класе који не ради ништа. Сврха конструктора је у томе да за објекат који се креира изврши иницијализацију нестатичких атрибута, тј. нестатичким атрибутима додељује неке вредности.
Конструктор има две специфичне особине:
- има исти назив као и класа
- нема никакву повратну вредност
- може имати произвољан број параметар, укључујући и 0 ( без параметара )
Конструктор се позива кад год креирамо објекат.


public class Pristaniste
{
    //Podrazumevani konstruktor klase Pristaniste, koji ne radi nista
    public Pristaniste()
    {
	
    }
	
    //Kreiranje objekta klase Brod
    Brod ug = new Brod();
	
    //Kreiranje objekta klase Brod, 
    //poziva se konstruktor sa jednim parametrom cija je vrednost broj 5
    Brod ug = new Brod(5);	
	
    //Ostali clanovi klase Pristaniste
	
    public class Brod
    {
        //Kreiranje objekta klase Sidro	
        Sidro ug1 = new Sidro();
        
        //Promenljive klase Brod
        public int brPosade;
		
        //Podrazumevani konstruktor klase Brod
        public Brod()
        {	

        }
		
        //Konstruktor klase Brod, koji atribut brPosade postavlja na vrednost r
        public Brod(int r)
        {
            //Da bi smo pristupili promenljivoj brPosade, koristimo kljucnu rec this
            this.brPosade = r;
        }
        //Ostali clanovi klase Brod
        public class Sidro
        {		
            //Promenljiva klase Sidro kojom je definisana tezina sidra
            public int tezina = 10;
			
            //Podrazumevani konstruktor klase Sidro
            public Sidro()
            {	

	    }			
			
            //Ostali clanovi klase Sidro
        }
    }
} 

Угњеждене класе се користе за дефинисање објеката, који имају неку повезаност са објектима спољашње класе, што ћемо покушати објаснити у следећим примерима.

Пример 1. Креирати класу Roditelj која ће у себи имати једино угњеждену класу Dete, чије ће класне променљиве бити ime и godina, а метод ће враћати име и број година детета. Написати и програм који ће креирати одговарајуће објекте и позивати методе.

Решење:

Направити класу Roditelj. С обзиром да сваки родитељ има децу, тако ће и наша класа Roditelj имати угњеждену класу Dete. У овом примеру класа Roditelj, неће имати других чланова осим угњеждене класе Dete и подразумеваног конструктора, који ће бити празан. Класу Dete одређује
string ime;
име уносимо са улаза
int godina;
број година детета, ћемо добити случајним избором једног од ограниченог скупа бројева, користећи већ дефинисану класу Random. Mетод Next(), класе Random, враћа вредност типа int која је у граници између 0 и вредности прослеђене као аргумент. Нпр.


//i će dobiti vrednost nekog od brojeva 0,1,2,3,...,8;
int i = Random.Next(9);

public Dete(string ime);
конструктор класе Dete, који додељује имену детета име које ћемо унети са улаза и број година додељује број које ћемо добити случајним избором неког броја < 15
public string ToString();
функција која враћа ime
Потрбено је да направимо форму Form1 (Слика 9.26.).

  1. label1 - у овој лабели ћемо написати "Ime deteta"
  2. textBox1 - у ово поље ћемо уписати име детета
  3. button1 - ово је наше контролно дугме и на њему ћемо написати DETE
  4. label2 - у овој лабели ће се исписивати име детета и број година
Слика 9.26. Изглед форме пре преименовања

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    //Funkcija koja se poziva kada se klikne na button "Izaberi"
    private void button1_Click(object sender, EventArgs e)
    {
        string ime = textBox1.Text;
        //Kreiramo objekat klase Roditelj
        Roditelj o = new Roditelj();
        //Kreiramo objekat klase Dete
        Roditelj.Dete rd = new Roditelj.Dete(ime);
        //Pomocu objekta rd pristupamo funkciji koja je definisana u klasi Dete
        //U label2 upisujemo ime deteta i broj godina
        label2.Text = rd.toString();
    }
    //Definisemo klasu Roditelj
    public class Roditelj
    {
        //Podrazumevani konstruktor za klasu Roditelj
        public Roditelj()
        {}
	
        //Ugnjezdena klasa Dete
        public class Dete
	{			
            //Kreiramo objekat klase Random
            private Random izbor = new Random();
            //Svako dete ima isto ime Vera               
            private string ime;
            private int godina;
             
            //Podrazumevani konstruktor za klasu Dete
            public Dete(string ime)
            {
                //Definisemo celobrojnu promenljivu index,
                //koja dobija vrednost slucajnog broja od 0 do 15
                int index = izbor.Next(15); 
                //Promenljiva godina dobija vrednost 1 + index
                godina = 1 + index;
                this.ime = ime;
            }
            //Definicija funkcije koja je tipa string, vraca ime deteta i broj godina tog deteta
            public string toString()
            {

                return "Zovem se " + ime + ", imam " + godina + " godina";
            }
        }
    }
}
	
Када покренемо апликацију из радног окружења помоћу тастера F5 отвара нам се форма. Уносимо неко име у textBox1 и кликом на дугме DETE у label2 ће се додати име детета и случајно изабран број година детета.
Слика 9.27. Резултат рада програма

Пример 2. Претходни пример допунити тако што ће класа Roditelj имати три класне променљиве - imeRoditelja, brdece и ime, конструктора и методе које враћају број деце. Потом написати програм у коме ће се креирати одговарајући објекти и позивати методе.

Решење:

У следећем примеру се надовезујемо на Пример 1, с тим што ћемо сада "обогатити" и нашу класу Roditelj, додавајући јој променљиве:
string imeRoditelja; string ime; int brdece; private static Random izbor = new Random();
Као и функције:
public Roditelj(string imeRoditelja,string ime);
конструктор класе Roditelj
public string toString();
функција која враћа број деце које дати родитељ има
public string Deca();
функција која враћа име детета и број година (користећи угњеждену класу Dete)
За сваког родитеља случајним избором од 1 до 5 одређујемо колико он деце има.
Правимо форму Form1(Слика 9.28.). Кликом на button1 у label3 се исписује оно што враћају функције toString() и Deca() класе Roditelj, док се у label4 исписује резултат функције toStringD() класе Dete.

  1. label1 - у овај лабел ћемо написати Ime roditelja:
  2. textBox1 - у ово поље ће наш корисник да уноси одговарајући податак, тј. унеће било које име
  3. label2 - у овај лабел ћемо написати Ime deteta:
  4. textBox2 - у ово поље ће наш корисник да уноси одговарајући податак, тј. унеће било које име
  5. button1 - ово је наше контролно дугме и на њему ћемо написати Roditelj
  6. label3 - у овој лабели ћемо исписивати један од наших резултата
  7. label4 - овде ћемо исписивати други резултат нашег задатка
Слика 9.28. Изглед форме пре преименовања

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    //Funkcija koja se poziva kada se klikne na button Roditelj
    private void button1_Click(object sender, EventArgs e)
    {
        //Kreiranje objekta klase Roditelj
        Roditelj o = new Roditelj(textBox1.Text);
        //Kreiranje objekta klase Dete
        Roditelj.Dete rd = new Roditelj.Dete("Vera");
        //Proveravamo da li je nesto uneto u textBox
        //Ukoliko nije, program vraca poruku da nije uneto ime roditelja			
        if (textBox1.Text == "" || texBox2.Text == "")
        MessageBox.Show( "Niste uneli ime roditelja ili ime deteta!!!");
        //Inace, ako je uneto ime roditelja, poziva se funkcija toString() klase Roditelj
        else
        {
            //Koja ispisuje ime roditelja i imena sve dece koje taj roditelj ima
            label3.Text = o.toString() + ".\nSamo " + o.Deca() + "\n je usvojeno dete";
            label4.Text = "Zovem se " + rd.toStringD();
        }
        
    }
}

public class Roditelj 
{
      
    private static Random izbor =  new Random();
  
    //Svaki roditelj ima svoje ime 
    private string imeRoditelja;
    //Broj dece koje ima dati roditelj 
    private int brdece; 
    //Svako dete ima svoje ime 
    private string ime;		

    public Roditelj()
    { 
    }
		
		
    //Konstruktor koji ima listu parametara, u ovom slucaju su dva parametara 
    //imeRoditelja i ime, oba tipa string
    public Roditelj(string imeRoditelja,string ime)
    {
        //Promenljivoj imeRoditelja se dodeljuje ime koje ce biti uneto sa ulaza
        this.imeRoditelja = imeRoditelja;
        //Promenljivoj ime se dodeljuje ime koje ce biti uneto sa ulaza
        this.ime = ime;
        //Promenljivoj index dodeljujemo slucajno izabran broj
        int index = izbor.Next(5);
        //Promenljivoj brdece dodeljujemo vrednost promenljive index
        brdece = index;
    }
    public string Deca()
    {
        //Kreiranje objekta klase Dete
        Dete d = new Dete(ime);
			
        //Vracamo vrednost funkcije toStringD klase Dete
        return d.toStringD();
    }
    //Funkcija koja vraca broj dece za unesenog roditelja
    public string toString()
    {
        //Definisemo promenljivu rez tipa String, u koju cemo smestiti
        //imeRoditelja i imena dece
        string rez = imeRoditelja + " ima " + brdece + ". dece";
        //Vracamo dobijeni rezultat
        return rez;
    }	
			
    //Ugnjezdena klasa
    public class Dete
    {
        //Svako dete ima svoj broj godina
        private int godina;
        //Svako dete ima svoje ime			
	private string ime;
             
        public Dete(string ime)
        {	       
            //Pristup statickoj clanici "izbor" spoljasnje klase, moguc je i iz nestaticke
            //ugnjezdene klase, bira se slucajan broj od 0 do 25
            int index = izbor.Next(25); 
					
            //Broj godina deteta se postavlja na 1+index
            godina = 1 + index;
            //Promenljivoj ime se dodeljuje ime koje ce biti uneto sa ulaza
            this.ime = ime;
        }
        //Funkcija koja vraca ime i godine deteta
        public String toString()
        {
            return ime + ", starosti" + godina + " god";
        }
    }	
}

Када покренемо апликацију из радног окружења помоћу тастера F5 отвара нам се форма. Kликом на дугме Roditelj у label3 ће се исписати резултат функција класе Roditelj, а у label4 ће се исписати резултат функције из класе Dete.
Слика 9.29. Резултат рада програма

Надамо се да смо кроз претходне примере успели колико толико да вам приближимо појам угњеждене класе. Уколико имате још неких недоумица око ове теме, покушајте да их решите тако што ћете погледати и урадити и друге примере које смо вам оставили, у оквиру ове теме.