Java では、一部のクラスにはその中に他のクラスを含めることができます。このようなクラスはネストされたクラスと呼ばれます。他のクラス内で定義されたクラスは、通常、静的と非静的の 2 つのカテゴリに分類されます。入れ子になった非静的クラスは内部と呼ばれます。静的として宣言されたネストされたクラスは、静的ネストされたクラスと呼ばれます。実際、ここでは複雑なことは何もありませんが、用語はやや曖昧で、プロのソフトウェア開発者でさえ混乱することがあります。
入れ子クラスと内部クラス
したがって、他のクラス内にあるすべてのクラスは、ネストされたクラスと呼ばれます。class OuterClass {
...
class NestedClass {
...
}
}
静的ではない入れ子クラスは内部クラスと呼ばれ、静的クラスは静的入れ子クラスと呼ばれます。
class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}
したがって、すべての内部クラスはネストされますが、すべてのネストされたクラスが内部クラスであるわけではありません。これらが主な定義です。内部クラスは、Java のセキュリティ メカニズムの一種です。通常のクラスをプライベート アクセス修飾子に関連付けることはできないことがわかっています。ただし、クラスが別のクラスのメンバーである場合、内部クラスをプライベートにすることができます。この機能は、プライベート クラス メンバーにアクセスするためにも使用されます。
内部クラスの例
そこで、いくつかのクラスを作成し、その中に別のクラスを作成してみましょう。ある種のモジュール式ゲームコンソールを想像してください。「ボックス」自体があり、そこに特定のモジュールを接続できます。たとえば、ゲーム コントローラー、ハンドル、VR ヘルメットなどは、通常、コンソール自体がなければ機能しません。ここに GameConsole クラスがあります。これには 2 つのフィールドと 1 つのメソッド ( start() )があります。GameCosoleと私たちが使い慣れているクラスの違いは、内部GameControllerクラスがあることです。public class GameConsole {
private String model;
private int weight;
public void run() {
System.out.println("Game console is on");
}
public class GameController {
private String color;
public void start() {
System.out.println("start button is pressed");
}
public void x() {
System.out.println("x button is pressed");
}
public void y() {
System.out.println("y button is pressed");
}
public void a() {
System.out.println("a button is pressed");
}
public void b() {
System.out.println("b button is pressed");
}
public void mover() {
System.out.println("mover button is pressed");
}
}
}
この時点で、なぜこれらのクラスを「個別」にしないのかと疑問に思うかもしれません。入れ子にする必要はありません。確かにそれは可能です。むしろ、それはクラスの使用という観点から見たクラスの正しい設計に関するものです。内部クラスは、別のエンティティと密接にリンクしているエンティティをプログラム内で強調表示するために作成されます。コントローラーや VR ヘルメットなどは、コンソールのコンポーネントです。はい、本体とは別に購入できますが、それなしでは使用できません。これらすべてのクラスを別個のパブリック クラスにすると、プログラムには、たとえば次のコードが含まれる可能性があります。
public class Main {
public static void main(String[] args) {
GameController controller = new GameController();
controller.x();
}
}
コントローラー自体はコンソールなしでは機能しないため、この場合に何が起こるかは不明です。ゲームコンソールオブジェクトを作成しました。そのサブオブジェクト、つまりゲーム コントローラーを作成しました。これで、正しいキーを押すだけでプレイできるようになりました。必要なメソッドは適切なオブジェクトで呼び出されます。すべてがシンプルで便利です。この例では、ゲーム コントローラーを抽出することでカプセル化が強化され (対応するクラス内のコンソール部分の詳細が非表示になります)、より詳細な抽象化が可能になります。しかし、たとえば、VR ヘルメットやコントローラーを個別に購入できる店舗をシミュレートするプログラムを作成すると、この例は失敗します。そこでゲームコントローラーを別途作成した方が良いでしょう。別の例を見てみましょう。内部クラスをプライベートにしても外部クラスから呼び出せることは上で述べました。以下はそのようなクラスの例です。
class OuterClass {
// inner class
private class InnerClass {
public void print() {
System.out.println("We are in the inner class...");
}
}
// method of outer class. We are create an inner class from the method of outer one
void display() {
InnerClass inner = new InnerClass();
inner.print();
}
}
ここで、OuterClassは外部クラス、InnerClassは内部クラス、display()は内部クラスのオブジェクトを作成するメソッドです。次に、 display()メソッドを呼び出す main メソッドを含むデモ クラスを作成しましょう。
public class OuterDemoMain {
public static void main(String args[]) {
// create an object of the outer class
OuterDemo outer = new OuterDemo();
outer.display();
}
}
このプログラムを実行すると、次の結果が得られます。
私たちはインナークラスにいます...
内部クラスの分類
内部クラス自体、または入れ子になった非静的クラスは 3 つのグループに分類されます。- 内部クラスはそのままです。GameConsoleとGameController の例で上で示したように、非静的クラスが 1 つだけ、もう 1 つの非静的クラス内にあります。
- メソッドローカル内部クラスはメソッド内のクラスです。
- 匿名のインナークラス。
メソッドローカルの内部クラス
Java では、メソッド内にクラスを記述することができ、それはローカル型です。ローカル変数と同様に、内部クラスのスコープはメソッド内に制限されます。メソッドローカル内部クラスは、内部クラスが定義されているメソッド内でのみ作成できます。ローカル メソッドの内部クラスの使用方法を示します。public class OuterDemo2 {
//instance method of the outer class OuterDemo2
void myMethod() {
String str = "and it's a value from OuterDemo2 class' myMethod ";
// method-local inner class
class methodInnerDemo {
public void print() {
System.out.println("Here we've got a method inner class... " );
System.out.println(str);
}
}
// Access to the inner class
methodInnerDemo inn = new methodInnerDemo();
inn.print();
}
}
ここで、 outer()メソッド を呼び出す main メソッドを含むデモ クラスを作成します。
public class OuterDemoMain {
public static void main(String args[]) {
OuterDemo2 outer = new OuterDemo2();
outer.myMethod();
}
}
出力は次のとおりです。
ここにはメソッドの内部クラスがあります...これは、OuterDemo2 クラスの myMethod からの値です。
匿名の内部クラス
クラス名を指定せずに宣言された内部クラスは、匿名内部クラスと呼ばれます。匿名の内部クラスを宣言すると、すぐにインスタンス化されます。通常、このようなクラスは、クラスまたはインターフェイス メソッドをオーバーライドする必要がある場合に使用されます。abstract class OuterDemo3 {
public abstract void method();
}
class outerClass {
public static void main(String args[]) {
OuterDemo3 inner = new OuterDemo3() {
public void method() {
System.out.println("Here we've got an example of an anonymous inner class");
}
};
inner.method();
}
}
出力は次のとおりです。
ここに匿名の内部クラスの例があります...
引数としての匿名内部クラス
匿名の内部クラスを引数としてメソッドに渡すこともできます。ここに一例を示します。interface OuterDemo4 {
String hello();
}
class NewClass {
// accepts the object of interface
public void displayMessage(OuterDemo4 myMessage) {
System.out.println(myMessage.hello());
System.out.println("example of anonymous inner class as an argument");
}
public static void main(String args[]) {
NewClass newClass = new NewClass();
//here we pass an anonymous inner class as an argument
newClass.displayMessage(new OuterDemo4() {
public String hello() {
return "Hello!";
}
});
}
}
出力は次のとおりです。
こんにちは!引数としての匿名内部クラスの例
学んだことをさらに強化するには、Java コースのビデオ レッスンを視聴することをお勧めします。
GO TO FULL VERSION