Javaのネストされたクラス
1. 序章
このチュートリアルは、Java言語のネストされたクラスの簡単で的確な紹介です。
簡単に言えば、Javaでは他のクラス内にクラスを定義できます。 ネストされたクラスを使用すると、1つの場所でのみ使用されるクラスを論理的にグループ化し、より読みやすく保守しやすいコードを記述し、カプセル化を増やすことができます。
始める前に、この言語で使用できるネストされたクラスのいくつかのタイプを見てみましょう。
- 静的なネストされたクラス
- 非静的ネストクラス
- ローカルクラス
- 匿名クラス
次のセクションでは、これらのそれぞれについて詳しく説明します。
2. 静的にネストされたクラス
静的にネストされたクラスについて覚えておくべきいくつかのポイントを次に示します。
- 静的メンバーと同様に、これらはクラスのインスタンスではなく、それらを囲むクラスに属します
- 宣言にすべてのタイプのアクセス修飾子を含めることができます
- それらは、囲んでいるクラスの静的メンバーにのみアクセスできます
- 静的メンバーと非静的メンバーの両方を定義できます
静的なネストされたクラスを宣言する方法を見てみましょう。
public class Enclosing {
private static int x = 1;
public static class StaticNested {
private void run() {
// method implementation
}
}
@Test
public void test() {
Enclosing.StaticNested nested = new Enclosing.StaticNested();
nested.run();
}
}
3. 非静的ネストクラス
次に、非静的ネストクラスについて覚えておくべきいくつかの簡単なポイントを次に示します。
- それらは内部クラスとも呼ばれます
- 宣言にすべてのタイプのアクセス修飾子を含めることができます
- インスタンス変数やメソッドと同様に、内部クラスはそれを囲むクラスのインスタンスに関連付けられます
- 静的か非静的かに関係なく、囲んでいるクラスのすべてのメンバーにアクセスできます。
- 非静的メンバーのみを定義できます
内部クラスを宣言する方法は次のとおりです。
public class Outer {
public class Inner {
// ...
}
}
修飾子staticを使用してネストされたクラスを宣言すると、それは静的メンバーの1つになります。 それ以外の場合は、内部クラスです。 構文的には違いは単一のキーワード(つまり、 static )ですが、意味的には、これらの種類のネストされたクラスの間には大きな違いがあります。 内部クラスインスタンスは、それを囲むクラスインスタンスにバインドされているため、メンバーにアクセスできます。 ネストされたクラスを内部クラスにするかどうかを選択するときは、この問題に注意する必要があります。
内部クラスをインスタンス化するには、最初にそれを囲むクラスをインスタンス化する必要があります。
それをどのように行うことができるか見てみましょう:
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
次のサブセクションでは、いくつかの特別なタイプの内部クラスを示します。
3.1. ローカルクラス
ローカルクラスは特殊なタイプの内部クラスであり、クラスはメソッドまたはスコープブロック内で定義されます。
このタイプのクラスについて覚えておくべきいくつかのポイントを見てみましょう。
- 宣言にアクセス修飾子を含めることはできません
- それらは、囲んでいるコンテキストで静的メンバーと非静的メンバーの両方にアクセスできます
- インスタンスメンバーのみを定義できます
簡単な例を次に示します。
public class NewEnclosing {
void run() {
class Local {
void run() {
// method implementation
}
}
Local local = new Local();
local.run();
}
@Test
public void test() {
NewEnclosing newEnclosing = new NewEnclosing();
newEnclosing.run();
}
}
3.2. 匿名クラス
匿名クラスを使用すると、再利用可能な実装を作成しなくても、インターフェイスまたは抽象クラスの実装を定義できます。
匿名クラスについて覚えておくべきいくつかのポイントをリストしましょう:
- 宣言にアクセス修飾子を含めることはできません
- それらは、囲んでいるコンテキストで静的メンバーと非静的メンバーの両方にアクセスできます
- インスタンスメンバーのみを定義できます
- これらは、コンストラクターを定義したり、他のクラスやインターフェースを拡張/実装したりできない、ネストされたクラスの唯一のタイプです。
匿名クラスを定義するには、最初に単純な抽象クラスを定義しましょう。
abstract class SimpleAbstractClass {
abstract void run();
}
次に、匿名クラスを定義する方法を見てみましょう。
public class AnonymousInnerUnitTest {
@Test
public void whenRunAnonymousClass_thenCorrect() {
SimpleAbstractClass simpleAbstractClass = new SimpleAbstractClass() {
void run() {
// method implementation
}
};
simpleAbstractClass.run();
}
}
詳細については、Javaの匿名クラスに関するチュートリアルが役立つ場合があります。
4. シャドウイング
内部クラスのメンバーの宣言は、それらが同じ名前である場合、それを囲むクラスのメンバーのシャドウになります。
この場合、 this キーワードはネストされたクラスのインスタンスを参照し、外部クラスのメンバーは外部クラスの名前を使用して参照できます。
簡単な例を見てみましょう:
public class NewOuter {
int a = 1;
static int b = 2;
public class InnerClass {
int a = 3;
static final int b = 4;
public void run() {
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("NewOuterTest.this.a = " + NewOuter.this.a);
System.out.println("NewOuterTest.b = " + NewOuter.b);
System.out.println("NewOuterTest.this.b = " + NewOuter.this.b);
}
}
@Test
public void test() {
NewOuter outer = new NewOuter();
NewOuter.InnerClass inner = outer.new InnerClass();
inner.run();
}
}
5. シリアル化
ネストされたクラスをシリアル化しようとしているときにjava.io.NotSerializableExceptionを回避するには、次のことを行う必要があります。
- ネストされたクラスをstaticとして宣言します
- ネストされたクラスとそれを囲むクラスの両方にSerializableを実装させます
6. 結論
この記事では、ネストされたクラスとは何か、およびそれらのさまざまなタイプについて説明しました。 また、フィールドの可視性とアクセス修飾子がこれらの異なるタイプ間でどのように異なるかについても調べました。
いつものように、このチュートリアルの完全な実装は、GitHubのにあります。