Java - Ugniježđena i unutrašnje klasa (Nested and Inner Class)


U Javi možete definisati klasu u drugoj klasi. Takva klasa je poznata kao ugniježđena klasa. Pogledajmo primjer:

class OuterClass {
    // ...
    class NestedClass {
        // ...
    }
}

Postoje dvije vrste ugniježđenih klasa koje možete kreirati u Javi, a to su:

  • Nestatična ugniježđena klasa (unutrašnja klasa)
  • Statična ugniježđena klasa


Nestatična ugniježđena klasa (unutrašnja klasa)

Nestatična ugniježđena klasa je klasa u drugoj klasi. Ima pristup članovima zatvorene klase (vanjske klase). Uopšteno je poznat kao unutrašnja klasa. Budući da unutrašnja klasa postoji unutar vanjske klase, prvo morate instancirati vanjsku klasu kako biste napravili instancu unutrašnje klase. Evo primjera kako možete proglasiti interne klase u Javi.


Primjer 1: Unutrašnja klasa (Inner class)

class CPU {
    double price;
    // ugnježđena klasa (nested class)
    class Processor{

        // članovi ugniježđene klase (nested class)
        double cores;
        String manufacturer;

        double getCache(){
            return 4.3;
        }
    }

    // ugniježđena zaštićena klasa (nested protected class)
    protected class RAM{

        // članovi zaštićene ugniježđene klase (nested protected class)
        double memory;
        String manufacturer;

        double getClockSpeed(){
            return 5.5;
        }
    }
}

public class Main {
    public static void main(String[] args) {

        // kreiranje objekta CPU vanjske klase
        CPU cpu = new CPU();

       // kreiranje objekta unutrašnje klase Procesor pomoću vanjske klase
        CPU.Processor processor = cpu.new Processor();

        // kreiranje objekta RAM-a unutrašnje klase koristeći CPU vanjsku klasu
        CPU.RAM ram = cpu.new RAM();
        System.out.println("Predmemorija procesora = " + processor.getCache());
        System.out.println("Ram takt brzina = " + ram.getClockSpeed());
    }
}

U gornjem programu postoje dvije ugniježđene klase: Processor i RAM unutar vanjske klase: CPU. Unutrašnja klasu možemo proglasiti zaštićenom (protected). Zbog toga smo klasu RAM proglasili zaštićenom (protected). Unutar glavne klase:

  • Prvo smo kreirali instancu vanjske klase CPU-a nazvane cpu.
  • Koristeći instancu eksterne klase, kreirali smo objekte unutrašnjih klasa:
CPU.Processor processor = cpu.new Processor;
CPU.RAM ram = cpu.new RAM();


Pristup članovima vanjske klase unutar unutrašnje klase

Članovima vanjske klase možemo pristupiti pomoću this ključne riječi. Ako želite saznati više o this ključnoj riječi, posjetite lekciju Javu - this ključna riječ.


Primjer 2: Pristup članovima (Accessing Members)

class Car {
    String carName;
    String carType;

    // dodijivanje vrijednosti pomoću konstruktora
    public Car(String name, String type) {
        this.carName = name;
        this.carType = type;
    }

    // privatna metoda (private method)
    private String getCarName() {
        return this.carName;
    }

// unutrašnja klasa (inner class)
    class Engine {
        String engineType;
        void setEngine() {

           // Pristup carType svojstvu Car
            if(Car.this.carType.equals("4WD")){

                // Pozivanje metode getCarName() od Car
                if(Car.this.getCarName().equals("Crysler")) {
                    this.engineType = "Manji";
                } else {
                    this.engineType = "Veći";
                }

            }else{
                this.engineType = "Veći";
            }
        }
        String getEngineType(){
            return this.engineType;
        }
    }
}

public class Main {
    public static void main(String[] args) {

// kreiranje objekta vanjske klase Car
        Car car1 = new Car("Mazda", "8WD");

        // kreiranje objekta unutrašnje klase pomoću vanjske klase
        Car.Engine engine = car1.new Engine();
        engine.setEngine();
        System.out.println("Tip motora za 8WD= " + engine.getEngineType());

        Car car2 = new Car("Crysler", "4WD");
        Car.Engine c2engine = car2.new Engine();
        c2engine.setEngine();
        System.out.println("Tip motora za 4WD = " + c2engine.getEngineType());
    }
}

U gornjem programu imamo unutrašnju klasu nazvanu Engine unutar vanjske klase Car. Ovdje, primijetite sljedeću liniju koda:

if(Car.this.carType.equals("4WD")) {...}

Ključnu riječ this koristimo za pristup varijabli carType vanjske klase. Možda ste primijetili da smo umjesto this.carType koristili Car.this.carType. Ukoliko nismo spomenuli ime vanjske klase Car, onda će this ključna riječ predstavljati člana unutar unutrašnje klase. Slično tome, pristupamo i metodi vanjske klase iz unutrašnje klase.

if (Car.this.getCarName().equals("Crysler") {...}

Važno je napomenuti da, iako je getCarName() privatna metoda, možemo joj pristupiti iz unutrašnje klase.



Statična ugniježđena klasa (Static Nested Class)

U Javi takođe možemo definisati statičku klasu unutar druge klase. Takva klasa je poznata kao statička ugniježđena klasa (Static Nested Class). Statične ugniježđene klase ne nazivaju se statičkim unutrašnjim klasama.

Za razliku od interne klase (inner class), statička ugniježđena klasa ne može pristupiti varijablama člana vanjske klase. To je zato što statička ugniježđena klasa ne zahtijeva da kreirate instancu vanjske klase.

OuterClass.NestedClass obj = new OuterClass.NestedClass();

Ovdje stvaramo objekt statične ugniježđene klase jednostavnim korištenjem imena klase vanjske klase. Zbog toga se na vanjsku klasu ne može referencirati pomoću OuterClass.this.


Primjer 3: Statička unutrašnja klasa

class MotherBoard {

   // statična ugniježđena klasa (static nested class)
   static class USB{
       int usb2 = 2;
       int usb3 = 1;
       int getTotalPorts(){
           return usb2 + usb3;
       }
   }

}
public class Main {
   public static void main(String[] args) {

       // kreiranje objekta statičke ugniježđene klase
       // korištenje imena vanjske klase
       MotherBoard.USB usb = new MotherBoard.USB();
       System.out.println("Total Ports = " + usb.getTotalPorts());
   }
}

U gore navedenom programu stvorili smo statičku klasu nazvanu USB unutar klase MotherBoard. Primijetite liniju koda:

MotherBoard.USB usb = new MotherBoard.USB();

Ovdje kreiramo objekt USB koristeći ime vanjske klase. Sada, da vidimo što bi se dogodilo ako pokušate pristupiti članovima vanjske klase:


Primjer 4: Pristup članovima vanjske klase unutar statičke unutrašnje klase

class MotherBoard {
   String model;
   public MotherBoard(String model) {
       this.model = model;
   }

   // statična ugniježđena klasa
   static class USB{
       int usb2 = 2;
       int usb3 = 1;
       int getTotalPorts(){
           // pristupanje varijabilnom modelu eksterne klase
           if(MotherBoard.this.model.equals("MSI")) {
               return 4;
           }
           else {
               return usb2 + usb3;
           }
       }
   }
}
public class Main {
   public static void main(String[] args) {

       // stvaranje objekta statičke ugniježđene klase
       MotherBoard.USB usb = new MotherBoard.USB();
       System.out.println("Ukupno portova = " + usb.getTotalPorts());
   }
}

Kada pokušamo pokrenuti program, dobićemo grešku:

error: non-static variable this cannot be referenced from a static context

To je zato što ne koristimo objekt vanjske klase za stvaranje objekta unutrašnje klase. Zbog toga nema reference na Motherboard vanjske klase pohranjene u Motherboard.this.