Heim >Java >javaLernprogramm >Innere Klassen und anonyme Klassen in Java
Java-Innenklasse (Inner Class), ein ähnliches Konzept gibt es auch in C++, nämlich die verschachtelte Klasse (Nested Class). Auf den ersten Blick scheint die innere Klasse etwas überflüssig zu sein, und ihre Nützlichkeit ist für Anfänger möglicherweise nicht so nützlich Offensichtlich, aber mit einem tieferen Verständnis werden Sie feststellen, dass die Designer von Java wirklich gute Absichten in Bezug auf interne Klassen haben. Das Erlernen der Verwendung innerer Klassen ist Teil der Beherrschung der fortgeschrittenen Java-Programmierung, wodurch Sie Ihre Programmstruktur eleganter gestalten können. Lassen Sie uns es unter folgenden Gesichtspunkten einführen:
Erstes Treffen
public interface Contents { int value(); } public interface Destination { String readLabel(); } public class Goods { private class Content implements Contents { private int i = 11; public int value() { return i; } } protected class GDestination implements Destination { private String label; private GDestination(String whereTo) { label = whereTo; } public String readLabel() { return label; } } public Destination dest(String s) { return new GDestination(s); } public Contents cont() { return new Content(); } } class TestGoods { public static void main(String[] args) { Goods p = new Goods(); Contents c = p.cont(); Destination d = p.dest("Beijing"); } }
In diesem Beispiel sind die Klassen Content und GDestination innerhalb der Klasse Goods definiert und verfügen über geschützte und private Modifikatoren um Zugriffsebenen zu steuern. Der Inhalt stellt den Inhalt der Waren dar, und GDestination stellt den Bestimmungsort der Waren dar. Sie implementieren jeweils zwei Schnittstellen Content und Destination. In der folgenden Hauptmethode verwenden Sie direkt Contents c und Destination d, um zu operieren. Sie sehen nicht einmal die Namen dieser beiden internen Klassen! Auf diese Weise wird der erste Vorteil innerer Klassen widergespiegelt – das Verstecken von Vorgängen, von denen Sie nicht möchten, dass andere sie kennen, nämlich die Kapselung.
Gleichzeitig haben wir auch die erste Möglichkeit entdeckt, ein inneres Klassenobjekt außerhalb des Geltungsbereichs der äußeren Klasse zu erhalten, nämlich es mithilfe der Methoden seiner äußeren Klasse zu erstellen und zurückzugeben. Dies geschieht mit den Methoden cont() und dest() im obigen Beispiel. Gibt es also eine andere Möglichkeit? Das Syntaxformat lautet natürlich wie folgt:
outerObject=new outerClass(Constructor Parameters); outerClass.innerClass innerObject=outerObject.new InnerClass(Constructor Parameters);
Beachten Sie, dass Sie beim Erstellen eines nicht statischen inneren Klassenobjekts zuerst das entsprechende äußere Klassenobjekt erstellen müssen. Was den Grund betrifft, führt dies zu unserem nächsten Thema –
Nicht-statische innere Klassenobjekte haben Verweise auf ihre äußeren Klassenobjekte
Ändern Sie das Beispiel gerade leicht:
public class Goods { private valueRate=2; private class Content implements Contents { private int i = 11*valueRate; public int value() { return i; } } protected class GDestination implements Destination { private String label; private GDestination(String whereTo) { label = whereTo; } public String readLabel() { return label; } } public Destination dest(String s) { return new GDestination(s); } public Contents cont() { return new Content(); } }
Der geänderte Teil wird rot angezeigt. Hier fügen wir der Goods-Klasse eine private Mitgliedsvariable hinzu, die den Wertkoeffizienten der Ware darstellt. Sie wird damit multipliziert, wenn die value()-Methode des internen Klasseninhalts den Wert berechnet. Wir haben herausgefunden, dass value() auf valueRate zugreifen kann, was auch der zweite Vorteil innerer Klassen ist – ein inneres Klassenobjekt kann auf den Inhalt des äußeren Klassenobjekts zugreifen, das es erstellt hat, sogar auf private Variablen! Dies ist eine sehr nützliche Funktion, die uns beim Entwerfen mehr Ideen und Verknüpfungen bietet. Um diese Funktion zu erreichen, muss das innere Klassenobjekt einen Verweis auf das äußere Klassenobjekt haben. Wenn der Java-Compiler ein inneres Klassenobjekt erstellt, übergibt er implizit die Referenz an sein äußeres Klassenobjekt und behält sie bei. Dadurch kann das innere Klassenobjekt immer auf sein äußeres Klassenobjekt zugreifen. Aus diesem Grund müssen Sie zum Erstellen eines inneren Klassenobjekts außerhalb des Geltungsbereichs der äußeren Klasse zuerst dessen äußeres Klassenobjekt erstellen.
Jemand fragt sich vielleicht, was ich tun soll, wenn eine Mitgliedsvariable in der inneren Klasse denselben Namen hat wie eine Mitgliedsvariable in der äußeren Klasse, d. h. die Mitgliedsvariable mit demselben Namen in der äußeren Klasse blockiert? Es ist in Ordnung, Java verwendet das folgende Format, um Verweise auf externe Klassen auszudrücken:
outerClass.this
Damit haben wir keine Angst vor dieser Art der Abschirmung.
Statische innere Klassen
Wie gewöhnliche Klassen können auch innere Klassen statisch sein. Der Unterschied zu nicht statischen inneren Klassen besteht jedoch darin, dass statische innere Klassen keine externen Referenzen haben. Dies ist tatsächlich den verschachtelten Klassen in C++ sehr ähnlich. Der größte Unterschied zwischen internen Java-Klassen und verschachtelten C++-Klassen besteht natürlich darin, ob es aus gestalterischer Sicht und in einigen Details einen Unterschied gibt.
Darüber hinaus darf es in keiner nicht statischen inneren Klasse statische Daten, statische Methoden oder andere statische innere Klassen geben (die Verschachtelung innerer Klassen kann mehr als eine Ebene umfassen). Aber Sie können all dies in statischen inneren Klassen haben. Dies kann als zweiter Unterschied zwischen den beiden angesehen werden.
Partielle innere Klasse
Ja, die innere Java-Klasse kann auch lokal sein, sie kann innerhalb einer Methode oder sogar eines Codeblocks definiert werden.
public class Goods1 { public Destination dest(String s) { class GDestination implements Destination { private String label; private GDestination(String whereTo) { label = whereTo; } public String readLabel() { return label; } } return new GDestination(s); } public static void main(String[] args) { Goods1 g= new Goods1(); Destination d = g.dest("Beijing"); } }
Das Obige ist ein solches Beispiel. In der Methode dest definieren wir eine innere Klasse, und schließlich gibt diese Methode das Objekt dieser inneren Klasse zurück. Wenn wir nur ein Objekt einer inneren Klasse erstellen und es nach außen erzeugen müssen, können wir dies tun. Natürlich können in Methoden definierte innere Klassen das Design diversifizieren, und ihre Verwendung ist nicht darauf beschränkt.
Hier ist ein seltsameres Beispiel:
public class Goods2{ private void internalTracking(boolean b) { if(b) { class TrackingSlip { private String id; TrackingSlip(String s) { id = s; } String getSlip() { return id; } } TrackingSlip ts = new TrackingSlip("slip"); String s = ts.getSlip(); } } public void track() { internalTracking(true); } public static void main(String[] args) { Goods2 g= new Goods2(); g.track(); } }
Sie können kein Objekt dieser inneren Klasse außerhalb von if erstellen, da dies seinen Geltungsbereich überschritten hat. Während der Kompilierung wird die interne Klasse TrackingSlip jedoch gleichzeitig mit anderen Klassen kompiliert, mit der Ausnahme, dass sie über einen eigenen Gültigkeitsbereich verfügt und außerhalb dieses Gültigkeitsbereichs ungültig ist. Ansonsten unterscheidet sie sich nicht von anderen internen Klassen.
Anonyme innere Klassen
Die Syntaxregeln der anonymen inneren Klassen von Java mögen etwas seltsam erscheinen, ähneln aber anonymen Arrays, wenn Sie nur ein Objekt einer Klasse erstellen müssen und dies nicht müssen Verwenden Sie seinen Namen. Wenn Sie innere Klassen verwenden, können Sie den Code prägnant und klar gestalten. Seine grammatikalischen Regeln lauten wie folgt:
new interfacename(){......}; 或 new superclassname(){......};
Fahren wir mit dem folgenden Beispiel fort:
public class Goods3 { public Contents cont(){ return new Contents(){ private int i = 11; public int value() { return i; } }; } }
这里方法cont()使用匿名内部类直接返回了一个实现了接口Contents的类的对象,看上去的确十分简洁。
在java的事件处理的匿名适配器中,匿名内部类被大量的使用。例如在想关闭窗口时加上这样一句代码:
frame.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); } });
有一点需要注意的是,匿名内部类由于没有名字,所以它没有构造函数(但是如果这个匿名内部类继承了一个只含有带参数构造函数的父类,创建它的时候必须带上这些参数,并在实现的过程中使用super关键字调用相应的内容)。如果你想要初始化它的成员变量,有下面几种方法:
如果是在一个方法的匿名内部类,可以利用这个方法传进你想要的参数,不过记住,这些参数必须被声明为final。
将匿名内部类改造成有名字的局部内部类,这样它就可以拥有构造函数了。
在这个匿名内部类中使用初始化代码块。
为什么需要内部类?
java内部类有什么好处?为什么需要内部类?
首先举一个简单的例子,如果你想实现一个接口,但是这个接口中的一个方法和你构想的这个类中的一个方法的名称,参数相同,你应该怎么办?这时候,你 可以建一个内部类实现这个接口。由于内部类对外部类的所有内容都是可访问的,所以这样做可以完成所有你直接实现这个接口的功能。
不过你可能要质疑,更改一下方法的不就行了吗?
的确,以此作为设计内部类的理由,实在没有说服力。
真正的原因是这样的,java中的内部类和接口加在一起,可以的解决常被C++程序员抱怨java中存在的一个问题——没有多继承。实际上,C++的多继承设计起来很复杂,而java通过内部类加上接口,可以很好的实现多继承的效果。
java内部类总结
(1) 在方法间定义的非静态内部类:
● 外围类和内部类可互相访问自己的私有成员。
● 内部类中不能定义静态成员变量。
在外部类作用范围之外向要创建内部类对象必须先创建其外部类对象
(2) 在方法间定义的静态内部类:
● 只能访问外部类的静态成员。
静态内部类没有了指向外部的引用
(3) 在方法中定义的局部内部类:
● 该内部类没有任何的访问控制权限
● 外围类看不见方法中的局部内部类的,但是局部内部类可以访问外围类的任何成员。
● 方法体中可以访问局部内部类,但是访问语句必须在定义局部内部类之后。
● 局部内部类只能访问方法体中的常量,即用final修饰的成员。
(4) 在方法中定义的匿名内部类:
● 没有构造器,取而代之的是将构造器参数传递给超类构造器
当你只需要创建一个类的对象而且用不上它的名字时,使用匿名内部类可以使代码看上去简洁清楚。
更多Java中的内部类和匿名类 相关文章请关注PHP中文网!