Java Inner Class

Java inner class wordt gedefinieerd binnen de body van een andere class. Java inner class kan worden gedeclareerd als private, public, protected of met standaard toegang, terwijl een outer class alleen public of standaard toegang kan hebben. Java geneste classes worden verdeeld in twee typen.

  1. static nested class

    Als de geneste class statisch is, wordt deze een static nested class genoemd. Statische nested classes kunnen alleen toegang krijgen tot statische leden van de outer class. Een statische nested class is hetzelfde als een andere top-level class en is genest voor alleen verpakkingsgemak. Een statische class object kan worden gemaakt met de volgende statement:

    OuterClass.StaticNestedClass nestedObject =
         new OuterClass.StaticNestedClass();
    
  2. java binnenklasse

    Elke niet-statische geneste klasse staat bekend als een binnenklasse in Java. Een Java binnenklasse is gekoppeld aan het object van de klasse en kan alle variabelen en methoden van de buitenklasse benaderen. Omdat binnenklassen zijn gekoppeld aan de instantie, kunnen we geen statische variabelen in hen hebben. Het object van de Java binnenklasse maakt deel uit van het object van de buitenklasse, en om een instantie van de binnenklasse te maken, moeten we eerst een instantie van de buitenklasse maken. Een Java binnenklasse kan worden geïnstantieerd als volgt;

    OuterClass outerObject = new OuterClass();
    OuterClass.InnerClass innerObject = outerObject.new InnerClass();
    

Er zijn twee speciale soorten Java-binnenklassen.

  1. lokale binnenklasse

    Als een klasse wordt gedefinieerd in een methode, staat deze bekend als lokale binnenklasse. Aangezien de lokale binnenklasse niet is gekoppeld aan een object, kunnen we geen private, public of protected toegangsmodificatoren gebruiken. De enige toegestane modificatoren zijn abstract of final. Een lokale binnenklasse kan alle leden van de omhullende klasse en lokale definitieve variabelen in de scope waarin deze is gedefinieerd, benaderen. Daarnaast kan het ook een niet-definitieve lokale variabele van de methode waarin het is gedefinieerd, benaderen, maar deze niet wijzigen. Dus als je probeert de waarde van een niet-definitieve lokale variabele af te drukken, zal dit worden toegestaan, maar als je probeert de waarde ervan te wijzigen vanuit de methode van de lokale binnenklasse, krijg je compileerfout. Lokale binnenklasse kan worden gedefinieerd als:

    package com.journaldev.innerclasses;
    
    public class MainClass {
    
    	private String s_main_class;
    
    	public void print() {
    		String s_print_method = "";
    		// lokale binnenklasse binnen de methode
    		class Logger {
    			// toegang tot omhullende klasse variabelen
    			String name = s_main_class; 
    			// toegang tot niet-definitieve method variabelen
    			String name1 = s_print_method; 
    
    			public void foo() {
    				String name1 = s_print_method;
    				// Onderstaande code veroorzaakt compileerfout:
    				// Lokale variabele s_print_method gedefinieerd in een omhullende scope moet definitief of effectief definitief zijn
    				// s_print_method= ":";
    			}
    		}
    		// instantiëren van lokale binnenklasse in de methode om te gebruiken
    		Logger logger = new Logger();
    
    	}
    }
    

    We kunnen ook een lokale binnenklasse definiëren binnen elk blok, zoals een statisch blok, if-else blok, enz. In dit geval is de reikwijdte van de klasse echter zeer beperkt.

    public class MainClass {
    
    	static {
    		class Foo {
    			
    		}
    		Foo f = new Foo();
    	}
    	
    	public void bar() {
    		if(1 < 2) {
    			class Test {
    				
    			}
    			Test t1 = new Test();
    		}
    		// Hieronder zal een fout veroorzaken vanwege de reikwijdte van de klasse
    		//Test t = new Test();
    		//Foo f = new Foo();
    	}
    }
    
  2. anonieme innerlijke klasse

    Een lokale innerlijke klasse zonder naam staat bekend als anonieme innerlijke klasse. Een anonieme klasse wordt gedefinieerd en geïnstantieerd in één enkele verklaring. Anonieme innerlijke klassen breiden altijd een klasse uit of implementeren een interface. Aangezien een anonieme klasse geen naam heeft, is het niet mogelijk om een constructor voor een anonieme klasse te definiëren. Anonieme innerlijke klassen zijn alleen toegankelijk op het punt waar ze zijn gedefinieerd. Het is een beetje moeilijk om te definiëren hoe je een anonieme innerlijke klasse kunt maken, we zullen het gebruik in realtime zien in het testprogramma hieronder.

Hier is een java-klasse die laat zien hoe je een java innerlijke klasse, statische geneste klasse, lokale innerlijke klasse en een anonieme innerlijke klasse kunt definiëren. OuterClass.java

package com.journaldev.nested;

import java.io.File;
import java.io.FilenameFilter;

public class OuterClass {
    
    private static String name = "OuterClass";
    private int i;
    protected int j;
    int k;
    public int l;

    //Constructor van OuterClass
    public OuterClass(int i, int j, int k, int l) {
        this.i = i;
        this.j = j;
        this.k = k;
        this.l = l;
    }

    public int getI() {
        return this.i;
    }

    //Statische geneste klasse, kan toegang krijgen tot statische variabelen/methoden van OuterClass
    static class StaticNestedClass {
        private int a;
        protected int b;
        int c;
        public int d;

        public int getA() {
            return this.a;
        }

        public String getName() {
            return name;
        }
    }

    //Innerlijke klasse, niet-statisch en kan toegang krijgen tot alle variabelen/methoden van de buitenklasse
    class InnerClass {
        private int w;
        protected int x;
        int y;
        public int z;

        public int getW() {
            return this.w;
        }

        public void setValues() {
            this.w = i;
            this.x = j;
            this.y = k;
            this.z = l;
        }

        @Override
        public String toString() {
            return "w=" + w + ":x=" + x + ":y=" + y + ":z=" + z;
        }

        public String getName() {
            return name;
        }
    }

    //Plaatselijke innerlijke klasse
    public void print(String initial) {
        //Plaatselijke innerlijke klasse inside the method
        class Logger {
            String name;

            public Logger(String name) {
                this.name = name;
            }

            public void log(String str) {
                System.out.println(this.name + ": " + str);
            }
        }

        Logger logger = new Logger(initial);
        logger.log(name);
        logger.log("" + this.i);
        logger.log("" + this.j);
        logger.log("" + this.k);
        logger.log("" + this.l);
    }

    //Anonieme innerlijke klasse
    public String[] getFilesInDir(String dir, final String ext) {
        File file = new File(dir);
        //Anonieme innerlijke klasse implementing FilenameFilter interface
        String[] filesList = file.list(new FilenameFilter() {

            @Override
            public boolean accept(File dir, String name) {
                return name.endsWith(ext);
            }

        });
        return filesList;
    }
}

Hier is het testprogramma dat laat zien hoe de innerlijke klasse in Java geïnstantieerd en gebruikt kan worden. InnerClassTest.java

package com.journaldev.nested;

import java.util.Arrays;
//Geneste klassen kunnen worden gebruikt bij import voor eenvoudige instantiatie
import com.journaldev.nested.OuterClass.InnerClass;
import com.journaldev.nested.OuterClass.StaticNestedClass;

public class InnerClassTest {

    public static void main(String[] args) {
        OuterClass outer = new OuterClass(1,2,3,4);
        
        //Voorbeeld van statische geneste klasse
        StaticNestedClass staticNestedClass = new StaticNestedClass();
        StaticNestedClass staticNestedClass1 = new StaticNestedClass();
        
        System.out.println(staticNestedClass.getName());
        staticNestedClass.d=10;
        System.out.println(staticNestedClass.d);
        System.out.println(staticNestedClass1.d);
        
        //Voorbeeld van innerlijke klasse
        InnerClass innerClass = outer.new InnerClass();
        System.out.println(innerClass.getName());
        System.out.println(innerClass);
        innerClass.setValues();
        System.out.println(innerClass);
        
        //Methode aanroepen met behulp van plaatselijke innerlijke klasse
        outer.print("Outer");
        
        //Methode aanroepen met behulp van anonieme innerlijke klasse
        System.out.println(Arrays.toString(outer.getFilesInDir("src/com/journaldev/nested", ".java")));
        
        System.out.println(Arrays.toString(outer.getFilesInDir("bin/com/journaldev/nested", ".class")));
    }

}

Hier is de uitvoer van het bovenstaande Java Inner Class-voorbeeldprogramma.

OuterClass
10
0
OuterClass
w=0:x=0:y=0:z=0
w=1:x=2:y=3:z=4
Outer: OuterClass
Outer: 1
Outer: 2
Outer: 3
Outer: 4
[NestedClassTest.java, OuterClass.java]
[NestedClassTest.class, OuterClass$1.class, OuterClass$1Logger.class, OuterClass$InnerClass.class, OuterClass$StaticNestedClass.class, OuterClass.class]

Merk op dat bij het compileren van OuterClass afzonderlijke klassen worden gemaakt voor de innerlijke klasse, de plaatselijke innerlijke klasse en de statische geneste klasse.

Voordelen van Java Inner Class

  1. Als een klasse slechts nuttig is voor één klasse, is het logisch om deze genest en samen te houden. Het helpt bij het verpakken van de klassen.
  2. Java inner-klassen implementeren encapsulatie. Let op dat inner-klassen toegang hebben tot privéleden van de buitenklasse en tegelijkertijd kunnen we de inner-klasse verbergen voor de buitenwereld.
  3. Het houden van de kleine klasse binnen top-level klassen plaatst de code dichter bij waar het wordt gebruikt en maakt de code leesbaarder en onderhoudbaarder.

Dat is alles voor Java inner class.

Source:
https://www.digitalocean.com/community/tutorials/java-inner-class