Programování

Statické třídy a vnitřní třídy v Javě

Vnořené třídy jsou třídy, které jsou deklarovány jako členové jiných tříd nebo oborů. Vnoření tříd je jedním ze způsobů, jak lépe uspořádat kód. Řekněme například, že máte nevnořenou třídu (známou také jako třída nejvyšší úrovně), který ukládá objekty do měnitelného pole, za kterým následuje třída iterátoru, která vrací každý objekt. Spíše než znečišťovat jmenný prostor třídy nejvyšší úrovně, můžete deklarovat třídu iterátoru jako člena třídy kolekce s měnitelnými poli. Funguje to, protože tyto dva spolu úzce souvisejí.

V Javě jsou vnořené třídy kategorizovány jako buď statické členské třídy nebo vnitřní třídy. Vnitřní třídy jsou nestatické členské třídy, místní třídy nebo anonymní třídy. V tomto kurzu se naučíte pracovat se statickými třídami členů a třemi typy vnitřních tříd v kódu Java.

Zabraňte úniku paměti ve vnořených třídách

Podívejte se také na tip Java přidružený k tomuto kurzu, kde se dozvíte, proč jsou vnořené třídy zranitelné únikem paměti.

Statické třídy v Javě

V mém Java 101 tutoriál Třídy a objekty v Javě jste se naučili deklarovat statická pole a statické metody jako členy třídy. V Inicializaci třídy a objektu v Javě jste se naučili deklarovat statické inicializátory jako členy třídy. Nyní se naučíte, jak deklarovat statické třídy. Formálně známý jako statické členské třídy, jsou to vnořené třídy, které deklarujete na stejné úrovni jako tyto další statické entity pomocí statický klíčové slovo. Zde je příklad statické deklarace třídy člena:

 třída C {statický int f; static void m () {} static {f = 2; } statická třída D {// members}} 

Tento příklad představuje třídu nejvyšší úrovně C se statickým polem Fstatická metoda m (), statický inicializátor a statická třída členů D. Všimněte si toho D je členem C. Statické pole Fstatická metoda m ()a statický inicializátor jsou také členy C. Protože všechny tyto prvky patří do třídy C, je znám jako uzavírající třídu. Třída D je známý jako uzavřená třída.

Pravidla pro krytí a přístup

Ačkoli je uzavřená, statická členská třída nemůže přistupovat k polím instance uzavírající třídy a vyvolat její metody instance. Může však přistupovat ke statickým polím obklopující třídy a vyvolat její statické metody, dokonce i ty členy, které jsou deklarovány soukromé. K prokázání výpis 1 deklaruje EnclosingClass s vnořeným SMClass.

Výpis 1. Deklarace statické členské třídy (EnclosingClass.java, verze 1)

 třída EnclosingClass {private static String s; private static void m1 () {System.out.println (s); } static void m2 () {SMClass.accessEnclosingClass (); } statická třída SMClass {static void accessEnclosingClass () {s = "Volano z metody accessEnclosingClass () SMClass"; ml (); } void accessEnclosingClass2 () {m2 (); }}} 

Výpis 1 deklaruje třídu nejvyšší úrovně s názvem EnclosingClass s polem třídy s, třídní metody m1 () a m2 ()a statická třída členů SMClass. SMClass deklaruje metodu třídy accessEnclosingClass () a instance metody accessEnclosingClass2 (). Mějte na paměti následující:

  • m2 ()Vyvolání SMClassje accessEnclosingClass () metoda vyžaduje SMClass. prefix protože accessEnclosingClass () je deklarováno statický.
  • accessEnclosingClass () má přístup EnclosingClassje s pole a zavolat jeho m1 () metoda, přestože obě byly deklarovány soukromé.

Výpis 2 představuje zdrojový kód souboru SMCDemo třída aplikace, která ukazuje, jak vyvolat SMClassje accessEnclosingClass () metoda. Také ukazuje, jak vytvořit instanci SMClass a vyvolat jeho accessEnclosingClass2 () metoda instance.

Výpis 2. Vyvolání metod třídy statického člena (SMCDemo.java)

 public class SMCDemo {public static void main (String [] args) {EnclosingClass.SMClass.accessEnclosingClass (); EnclosingClass.SMClass smc = nový EnclosingClass.SMClass (); smc.accessEnclosingClass2 (); }} 

Jak je znázorněno v Seznamu 2, pokud chcete vyvolat metodu třídy nejvyšší úrovně z uzavřené třídy, musíte před název uzavřené třídy uvést název její uzavřené třídy. Podobně za účelem vytvoření instance uzavřené třídy musíte před název této třídy uvést předponu s názvem její uzavřené třídy. Potom můžete metodu instance vyvolat běžným způsobem.

Zkompilujte výpisy 1 a 2 následujícím způsobem:

 javac * .java 

Když kompilujete uzavírající třídu, která obsahuje třídu statického člena, kompilátor vytvoří soubor třídy pro třídu statického člena, jejíž název se skládá z názvu její obklopující třídy, znaku znaku dolaru a názvu třídy statického člena. V tomto případě kompilace vede k EnclosingClass $ SMCClass.class a EnclosingClass.class.

Spusťte aplikaci následujícím způsobem:

 java SMCDemo 

Měli byste dodržovat následující výstup:

 Voláno z metody SMClass accessEnclosingClass () Volano z metody SMClass accessEnclosingClass () 

Příklad: Statické třídy a Java 2D

Java knihovna standardní třídy je runtime knihovna souborů tříd, která ukládá kompilované třídy a další referenční typy. Knihovna obsahuje řadu příkladů statických tříd členů, z nichž některé se nacházejí ve třídách Java 2D geometrických tvarů umístěných v souboru java.awt.geom balík. (O balíčcích se dozvíte v dalším Java 101 tutorial.)

The Ellipse2D třída nalezena v java.awt.geom popisuje elipsu, která je definována rámcovým obdélníkem, pokud jde o levý horní roh (x, y) spolu s rozsahy šířky a výšky. Následující fragment kódu ukazuje, že architektura této třídy je založena na Plovák a Dvojnásobek statické členské třídy, které obě podtřídy Ellipse2D:

 public abstract class Ellipse2D extends RectangularShape {public static class Float extends Ellipse2D implements Serializable {public float x, y, width, height; public Float () {} public Float (float x, float y, float w, float h) {setFrame (x, y, w, h); } public double getX () {return (double) x; } // další metody instance} public static class Double extends Ellipse2D implements Serializable {public double x, y, width, height; public Double () {} public Double (double x, double y, double w, double h) {setFrame (x, y, w, h); } public double getX () {return x; } // další metody instance} public boolean obsahuje (double x, double y) {// ...} // další metody instance sdílené Floatem, Double a dalšími // podtřídami Ellipse2D} 

The Plovák a Dvojnásobek třídy se prodlužují Ellipse2D, poskytující plovoucí desetinnou čárku a plovoucí desetinnou čárku s dvojitou přesností Ellipse2D implementace. Vývojáři používají Plovák ke snížení spotřeby paměti, zejména proto, že k vytvoření jedné 2D scény možná budete potřebovat tisíce nebo více těchto objektů. Používáme Dvojnásobek když je požadována větší přesnost.

Abstrakt nelze vytvořit instanci Ellipse2D třídy, ale můžete vytvořit instanci buď Plovák nebo Dvojnásobek. Můžete také prodloužit Ellipse2D popsat vlastní tvar založený na elipsě.

Jako příklad řekněme, že chcete zavést a Circle2D třída, která není přítomna v java.awt.geom balík. Následující fragment kódu ukazuje, jak byste vytvořili Ellipse2D objekt s implementací s plovoucí desetinnou čárkou:

 Ellipse2D e2d = nový Ellipse2D.Float (10.0f, 10.0f, 20.0f, 30.0f); 

Další fragment kódu ukazuje, jak byste vytvořili Ellipse2D objekt s implementací s plovoucí desetinnou čárkou s dvojitou přesností:

 Ellipse2D e2d = nový Ellipse2D.Double (10.0, 10.0, 20.0, 30.0); 

Nyní můžete vyvolat kteroukoli z metod deklarovaných v Plovák nebo Dvojnásobek vyvoláním metody na vrácené Ellipse2D odkaz (např. e2d.getX ()). Stejným způsobem můžete vyvolat kteroukoli ze společných metod Plovák a Dvojnásobek, a které jsou deklarovány v Ellipse2D. Příkladem je:

 e2d. obsahuje (2.0, 3.0) 

Tím je dokončen úvod do statických tříd členů. Dále se podíváme na vnitřní třídy, což jsou nestatické členské třídy, místní třídy nebo anonymní třídy. Naučíte se, jak pracovat se všemi třemi typy vnitřních tříd.

stáhnout Získat kód Stáhněte si zdrojový kód pro příklady v tomto výukovém programu. Vytvořil Jeff Friesen pro JavaWorld.

Vnitřní třídy, typ 1: Nestatické třídy členů

Naučili jste se dříve v Java 101 série jak deklarovat nestatické pole (instance), metody a konstruktory jako členy třídy. Můžete také deklarovat nestatické členské třídy, což jsou vnořené nestatické třídy, které deklarujete na stejné úrovni jako pole instance, metody a konstruktory. Zvažte tento příklad:

 třída C {int f; void m () {} C () {f = 2; } třída D {// členové}} 

Zde představujeme třídu nejvyšší úrovně C s polem instance F, instance metoda m (), konstruktor a nestatická členská třída D. Všechny tyto entity jsou členy třídy C, který je obklopuje. Na rozdíl od předchozího příkladu jsou však tyto entity instance přidruženy k instanceC a ne s C třída sama.

Každá instance nestatické členské třídy je implicitně přidružena k instanci její obklopující třídy. Metody instance nestatické členské třídy mohou volat metody instance uzavírající třídy a přistupovat k jejím polím instance. K prokázání tohoto přístupu výpis 3 deklaruje EnclosingClass s vnořeným NSMClass.

Výpis 3. Deklarovat uzavírající třídu pomocí vnořené nestatické třídy členů (EnclosingClass.java, verze 2)

 třída EnclosingClass {private String s; private void m () {System.out.println (s); } třída NSMClass {void accessEnclosingClass () {s = "Volano metodou NSMClass accessEnclosingClass ()"; m (); }}} 

Výpis 3 deklaruje třídu nejvyšší úrovně s názvem EnclosingClass s polem instance s, instance metoda m ()a nestatická třída členů NSMClass. Dále NSMClass deklaruje instanční metodu accessEnclosingClass ().

Protože accessEnclosingClass () je nestatický, NSMClass musí být vytvořena instance před voláním této metody. Toto vytvoření instance musí probíhat prostřednictvím instance EnclosingClass, jak je uvedeno v seznamu 4.

Výpis 4. NSMCDemo.java

 public class NSMCDemo {public static void main (String [] args) {EnclosingClass ec = new EnclosingClass (); ec.new NSMClass (). accessEnclosingClass (); }} 

Výpis 4 hlavní() metoda nejprve vytvoří instanci EnclosingClass a uloží jeho odkaz do lokální proměnné ec. The hlavní() metoda pak používá EnclosingClass odkaz jako předpona k Nový operátor za účelem vytvoření instance NSMClass. The NSMClass odkaz se poté použije k volání accessEnclosingClass ().

Měl bych použít 'new' s odkazem na uzavírající třídu?

Předpona Nový s odkazem na uzavírající třídu je vzácné. Místo toho obvykle zavoláte konstruktor uzavřené třídy z konstruktoru nebo metody instance její uzavřené třídy.

Zkompilujte výpisy 3 a 4 následovně:

 javac * .java 

Když kompilujete uzavírací třídu, která obsahuje nestatickou členskou třídu, kompilátor vytvoří soubor třídy pro nestatickou členskou třídu, jejíž název se skládá z názvu její uzavírající třídy, znaku znaku dolaru a nestatické členské třídy název. V tomto případě kompilace vede k EnclosingClass $ NSMCClass.class a EnclosingClass.class.

Spusťte aplikaci následujícím způsobem:

 java NSMCDemo 

Měli byste dodržovat následující výstup:

 Volá se metodou NSMClass accessEnclosingClass () 

Kdy (a jak) kvalifikovat „toto“

Kód uzavřené třídy může získat odkaz na instanci uzavřené třídy kvalifikováním vyhrazeného slova tento s názvem uzavírající třídy a operátorem přístupu členů (.). Například pokud kód uvnitř accessEnclosingClass () potřebné k získání odkazu na jeho EnclosingClass instance, to by specifikovalo EnclosingClass.this. Protože kompilátor generuje kód k provedení tohoto úkolu, je zadání této předpony vzácné.

Příklad: Nestatické členské třídy v HashMap

Knihovna standardních tříd zahrnuje nestatické členské třídy i statické členské třídy. V tomto příkladu se podíváme na HashMap třída, která je součástí Java Collections Framework v java.util balík. HashMap, který popisuje implementaci mapy s hashovací tabulkou, obsahuje několik nestatických tříd členů.

Například Sada klíčů nestatická členská třída popisuje množinu Pohled klíčů obsažených v mapě. Následující fragment kódu souvisí s přiloženým Sada klíčů třída do své HashMap uzavírající třída:

 veřejná třída HashMap rozšiřuje AbstractMap implementuje Map, Cloneable, Serializable {// různí členové finální třída KeySet rozšiřuje AbstractSet {// různí členové} // různí členové} 

The a syntaxe jsou příklady generika, sada souvisejících jazykových funkcí, které kompilátoru pomáhají vynucovat bezpečnost typů. V nadcházejícím představím generika Java 101 tutorial. Prozatím potřebujete vědět, že tyto syntaxe pomáhají kompilátoru vynutit typ klíčových objektů, které lze uložit na mapě a v sadě klíčů, a typ hodnotových objektů, které lze uložit na mapě.

HashMap poskytuje a keySet () metoda, která vytváří instanci Sada klíčů v případě potřeby vrátí tuto instanci nebo instanci uloženou v mezipaměti. Zde je kompletní metoda: