Java学習ノートの内部クラスとネストクラス


Javaでは、1つのクラス定義でもう1つのクラスを定義できます.これが内部クラスです.内部クラスを外部クラスのドメインと見なすことができ,多くの問題を理解するのに便利である.staticキーワードでクラスを修飾するかどうかによって、クラスを内部クラス(Inner Class)とネストクラス(Nested Class)に分けることもできます.
1.なぜ内部クラスが必要なのか
a.論理的に関連するクラスを組織する方法であり、一般的にこのような内部クラスは外部クラスとのみ関連している.
b.内部クラスが外部クラスのドメインにアクセスできるため、カプセル化性が向上する.
c.コードの可読性と管理性を向上させることができる.
2.内部クラス
a.内部クラスの作成
class Outer {
//        
class Inner {
//        
}
}

b.外部クラスへのリンク
内部クラスを外部クラスのドメインと見なすと,非staticであるため,内部クラスは外部クラスのあるオブジェクトに関連付けられている,すなわち既存の外部クラスオブジェクト,さらには内部クラスオブジェクトである.また、内部クラスはドメインであるため、特別な条件を必要とせずに外部クラスのすべてのメンバーにアクセスできます.
class Outer {
//         
private String name = "Outer";
public Inner getInner() {
return new Inner();
}
class Inner {
//         
void print() {
System.out.println(name);
}
}
public static void main(String[] args) {
//Inner inner1 = new Inner();                
Outer outer = new Outer();
Inner inner = outer.getInner();
inner.print();
}
}

Output:Outer
内部クラスはprivate修飾であるにもかかわらず、外部クラスのnameドメインにアクセスできることがわかります.Innerオブジェクトを直接作成する場合は、コンパイラがエラーを報告します.外部クラスのオブジェクトを介してn内部クラスのオブジェクトを取得すると、エラーは報告されません.
      c..これと.new
上のコードでは、外部クラスにメソッドを提供することで内部クラスオブジェクトを返すことがわかりますが、このメソッドだけが内部クラスオブジェクトを生成できますか?
実はもう一つの方法は、使うことです.new,以下のように
Outer outer=new Outer();
Inner inner2 = outer.new Inner();
inner2.print();

外部クラスオブジェクトを使用して内部クラスを作成できます.
1つのクラスでこのオブジェクトを使用したい場合はthisキーワードを使用できることを知っていますが、内部クラスで関連する外部クラスオブジェクトを使用したい場合は、どうすればいいですか?
外部クラス名の後にホームとthis(ClassName.this)を付けることができます.
class Outer {
//         
private String name = "Outer";
public Inner getInner() {
return new Inner();
}
void print() {
System.out.println("Outer:" + name);
}
class Inner {
//         
void print() {
System.out.println(name);
}
Outer outer() {
return Outer.this;
}
}
public static void main(String[] args) {
// Inner inner1 = new Inner();                
Outer outer = new Outer();
Inner inner = outer.new Inner();
inner.outer().print();
}
}

d.メソッドと役割ドメインにおける内部クラス
1つのクラスの内部で内部クラスを定義するほか、1つのメソッドまたは任意の役割ドメインで内部クラスを定義することもできます.このようにするには2つの理由があります.
1)ある種類のインタフェースを実現し、その参照を返すことができる
2)複雑な問題の解決を支援するクラスを作成し、このクラスが共通であることを望んでいない.
public interface Playable {
void play();
}
class Outer {
public Playable getPlayable() {
class Football implements Playable {
@Override
public void play() {
// TODO Auto-generated method stub
System.out.println("Play Football");
}
}
return new Football();
}
public static void main(String[] args) {
Outer outer = new Outer();
Playable playable = outer.getPlayable();
playable.play();
}
}

Output:Play Footballメソッドボディの内部で定義される内部クラスをローカル内部クラスと呼ぶ.
class Outer {
   public void test(boolean b) {
      if (b) {
         class Basketball implements Playable {
           @Override
           public void play() {
             // TODO Auto-generated method stub
             System.out.println("Play Basketball");
             }
         }
         new Basketball().play();
      }
   }
   public static void main(String[] args) {
        Outer outer = new Outer();
        outer.test(true);
   }
}

上記の例は、役割ドメインで定義された内部クラスです.
e.匿名内部クラス
class Outer {
private String name = "Outer";
//      
public Inner getInner() {
return new Inner() {
@Override
void print() {
// TODO Auto-generated method stub
System.out.println("     Inner:" + name);
}
};
}
class Inner {
void print() {
System.out.println("   Inner:" + name);
}
}
public static void main(String[] args) {
// Inner inner1 = new Inner();                
Outer outer = new Outer();
Inner inner = outer.getInner();
}
}

getInnerメソッドのメソッドボディが少しおかしいことがわかります.メソッドは、この戻り値を表すクラスの定義と戻り値の生成を結合します.また、このクラスは匿名であり、この奇妙な構文は「Innerから継承された匿名クラスのオブジェクトを作成する」ことを意味し、上記のコードではInnerベースクラスのprintメソッドを上書きしています.new式で返される参照は、自動的にInnerへの参照に変換されます.
継承といえば、初期化の問題が思い浮かぶ.上記のコードエクスポートクラスにはデフォルトのコンストラクタが使用されていますが、ベースクラスのコンストラクタにパラメータがある場合は、匿名の内部クラスのコンストラクタにもパラメータが必要です.
匿名の内部クラスに名前がないため、どのように初期化すればいいのでしょうか.これは、インスタンスの初期化によって解決できます.
匿名の内部クラスを定義し、外部で定義されたオブジェクトを使用する場合、コンパイラはパラメータ参照がfinalであることを要求します.Javaはセキュリティのため、匿名の内部クラスが外部の変数を修正する可能性があるため、使用者は知らないため、大きなエラーを引き起こす可能性があり、いつエラーが発生したのか分からないので、上記のコードに及ばないと思います.クラスでprintメソッドを書き直しましたが、使用者には効果がありません.エラーを避けるために、Javaは使用するパラメータをfinalでなければならないと規定しています.
3.ネストされたクラス
ネストされたクラスは内部クラスの定義と同じで、staticキーワード修飾が1つ増えただけです.同様にネストクラスをドメインと見なすと,静的ドメインはクラスに属し,すなわちネストクラスはオブジェクトから独立して存在することができる.同様に、クラスで外部クラスのドメインを使用したい場合は、クラスのドメイン、すなわちstaticドメインのみが使用され、特定のオブジェクトに関連するため、非staticドメインは使用できません.ネストされたクラスのオブジェクトを作成する場合は、周辺オブジェクトを作成する必要がなく、直接作成することもできます.
class Outer {
private String name = "Outer";
static int size = 3;
//    
static class NestedClass {
void print() {
// System.out.println(name);name     ,     
System.out.println(size);
}
}
public static void main(String[] args) {
NestedClass class1 = new NestedClass();
class1.print();
}
}

4.まとめ
a.内部クラスとネストクラスは、ネストされた階層にかかわらず、ネストされた周辺クラスに透過的にアクセスできるすべてのメンバーです.
b.内部クラスは非静的であり、周辺オブジェクトに関連し、既存の周辺オブジェクト、さらに内部クラスオブジェクトがある.
c.匿名内部クラスはエクスポートクラスであり、継承された初期化の問題に関連し、注意が必要である.また、安全のためにアクセスする外国語オブジェクトのパラメータはfinalでなければなりません.
d.ネストされたクラスは静的で、オブジェクトに関係なく個別に作成できます.また、ネストされたクラスの内部から非静的な周辺オブジェクトにアクセスすることはできません.