[java]匿名内部クラス

16747 ワード

JAvaの匿名の内部クラス:
    匿名の内部クラスつまり名前のない内部クラス    名前がないだけに、匿名の内部クラスは一度しか使用できません.通常はコードの作成を簡略化するために使用されます.    匿名の内部クラスを使用するには、親を継承するか、インタフェースを実装する必要があるという前提条件があります.
例1:匿名の内部クラスを使用しない抽象的な方法
abstract class Person {
    public abstract void eat();
}

class Child extends Person {
    public void eat() {
        System.out.println("eat something");
    }
}

public class Demo {
    public static void main(String[] args) {
        Person p = new Child();
        p.eat();
    }
}

実行結果:eat something
PersonクラスをChildで継承し,Childの一例を実現し,Personクラスへの参照に上方転換したが,ここでChildクラスが一度しか使用されていない場合,独立したクラスとして記述するのは面倒ではないか.このとき匿名の内部クラスが導入されました
例2:匿名内部クラスの基本実装
abstract class Person {
    public abstract void eat();
}

public class Demo {
    public static void main(String[] args) {
        Person p = new Person() {
            public void eat() {
                System.out.println("eat something");
            }
        };
        p.eat();
    }
}

実行結果:eat something
抽象クラスPersonの方法をかっこで直接実現することで,クラスの書き込みを省略でき,匿名の内部クラスはインタフェースにも使用できることが分かった.
例3:インタフェースで匿名の内部クラスを使用する
interface Person {
    public void eat();
}

public class Demo {
    public static void main(String[] args) {
        Person p = new Person() {
            public void eat() {
                System.out.println("eat something");
            }
        };
        p.eat();
    }
}

実行結果:eat something
上記の例から分かるように、1つのクラスが抽象的または1つのインタフェースであれば、そのサブクラスのメソッドが匿名の内部クラスを使用して最も一般的な状況を実現することができるのは、マルチスレッドの実装である.マルチスレッドを実現するにはThreadクラスを継承するかRunnableインタフェースを継承する必要があるからである.
例4:Threadクラスの匿名内部クラス実装
public class Demo {
    public static void main(String[] args) {
        Thread t = new Thread() {
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.print(i + " ");
                }
            }
        };
        t.start();
    }
}

実行結果:1 2 3 4 5
例5:Runnableインタフェースの匿名内部クラス実装
public class Demo {
    public static void main(String[] args) {
        Runnable r = new Runnable() {
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.print(i + " ");
                }
            }
        };
        Thread t = new Thread(r);
        t.start();
    }
}

実行結果:1 2 3 4 5
拡張:
Java内部クラス(Inner Class)、似たような概念はC++にもあります.それはネストクラス(Nested Class)です.一見内部が余計に見えますが、初心者にとってはそれほど顕著ではないかもしれませんが、深く理解するにつれて、Javaの設計者は内部クラスで本当に苦労しています.内部クラスの使用を学ぶことは、Javaの高度なプログラミングの一部であり、プログラム構造をより優雅に設計することができます.次に、例をいくつかの態様で説明します.
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");
    }
}

    この例ではクラスContentとGDestinationはクラスGoodsの内部に定義され,それぞれprotectedとprivate修飾子を持ってアクセスレベルを制御する.ContentはGoodsの内容を表し、GDestinationはGoodsの目的地を表します.2つのインタフェースContentとDestinationがそれぞれ実現されています.後のmainメソッドでは、Contents cとDestination dで直接操作し、この2つの内部クラスの名前さえ見えません!このように、内部クラスの最初のメリットは、他の人に知られたくない操作、すなわちパッケージ性を隠すことです.
    同時に,外部クラスの作用範囲外で内部クラスオブジェクトを得る最初の方法,すなわち,その外部クラスの方法を用いて作成して返すことも見いだした.前例のcont()とdest()の方法はこのようにします.では、他の方法はありませんか?もちろんあります.文法のフォーマットは次のとおりです.
outerObject=new outerClass(Constructor Parameters);

outerClass.innerClass innerObject=outerObject.new InnerClass(Constructor Parameters);

    注意静的でない内部クラスオブジェクトを作成する場合は、まず対応する外部クラスオブジェクトを作成する必要があります.理由については、非静的な内部クラスオブジェクトが外部クラスオブジェクトを指す参照があることについて、さっきの例を少し修正しました.
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();
    }
}

    ここではGoodsクラスにprivateメンバー変数valueRateを追加し,貨物の価値係数を意味し,内部クラスContentの方法value()で価値を計算する際にそれを乗じた.value()はvalueRateにアクセスできることを発見しました.これも内部クラスの2番目のメリットです.内部クラスオブジェクトは、プライベート変数を含む外部クラスオブジェクトのコンテンツにアクセスできます.これは非常に有用な特性であり、設計時により多くの考え方と近道を提供しています.この機能を実現するには、内部クラスオブジェクトに外部クラスオブジェクトへの参照が必要です.Javaコンパイラは,内部クラスオブジェクトを作成する際に,その外部クラスオブジェクトの参照も暗黙的に伝えて保存している.これにより、内部クラスオブジェクトは常に外部クラスオブジェクトにアクセスできます.また、外部クラスの役割範囲の外側で内部クラスオブジェクトを作成するには、外部クラスオブジェクトを作成する必要がある理由でもあります.
    内部クラスのメンバー変数が外部クラスのメンバー変数と同じ名前、つまり外部クラスの同じ名前のメンバー変数がブロックされたらどうしますか?大丈夫です.Javaでは、外部クラスの参照を次の形式で表します.  outerClass.thisがあれば、私たちはこのような遮蔽の状況を恐れません.
静的内部クラス
    通常のクラスと同様に、内部クラスにも静的なものがあります.ただし、非静的内部クラスと比較すると、静的内部クラスには外部への参照がないという違いがあります.これは実際にはC++のネストクラスと似ていますが、Java内部クラスとC++のネストクラスの最大の違いは、外部への参照があるかどうかという点であり、もちろん設計の観点や細部から違いがあります.
    それ以外に、任意の非静的内部クラスには、静的データ、静的メソッド、またはもう一つの静的内部クラスは存在しません(内部クラスのネストは1つ以上であってもよい).しかし、静的内部クラスでは、このすべてを持つことができます.これも両者の2番目の違いでしょう.
ローカル内部クラス
はい、Java内部クラスはローカルであってもよく、メソッドまたはコードブロック内で定義できます. 
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");
     }
}

    上はこのような例です.メソッドdestでは内部クラスを定義し,最後にこのメソッドによってこの内部クラスのオブジェクトを返す.内部クラスを使用するときに、オブジェクトを作成して外部に作成するだけでよい場合は、このようにできます.もちろん,メソッドに定義された内部クラスは設計を多様化させることができ,用途はそれだけではない.もっと奇妙な例があります 
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();
    }
}

    if以外にこの内部クラスのオブジェクトを作成することはできません.これは、その役割ドメインを超えているからです.しかし、コンパイル時には、内部クラスTrackingSlipは他のクラスと同様に同時にコンパイルされますが、それは独自の役割ドメインによって、この範囲を超えると無効になります.それ以外は他の内部クラスと区別されません.
匿名の内部クラス    JAvaの匿名内部クラスの構文規則は少し変に見えますが、匿名配列のように、クラスのオブジェクトを作成するだけで名前が使えない場合は、内部クラスを使用してコードを簡潔に見ることができます.構文規則は次のとおりです.  new interfacename(){......}; またはnew superclassname(){......};次に、例を先に示します. 
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内部クラスにはどんなメリットがありますか?なぜ内部クラスが必要ですか?
    まず簡単な例を挙げて、もしあなたがインタフェースを実現したいならば、しかしこのインタフェースの中の1つの方法とあなたが構想したこのクラスの中の1つの方法の名前、パラメータは同じで、あなたはどうすればいいですか?この場合、このインタフェースを実装する内部クラスを構築することができます.内部クラスは外部クラスのすべてのコンテンツにアクセスできるため、このインタフェースを直接実現するすべての機能を完了することができます.    しかし、方法を変えればいいのではないかと疑問に思うかもしれません.    確かに、これを設計内部類とする理由には説得力がない.    本当の原因はこのようにして、javaの中の内部クラスとインタフェースを合わせて、C++プログラマーによくjavaの中に存在する1つの問題に文句を言われることを解決することができます--多く継承していません.実際,C++のマルチ継承は複雑に設計されているが,javaは内部クラスにインタフェースを加えることで,マルチ継承の効果をうまく実現できる.
 JAva内部クラスまとめ(1) メソッド間で定義される非静的内部クラス:         ・周辺クラスと内部クラスは、互いに自分のプライベートメンバーにアクセスすることができる.       ・内部クラスでは静的メンバー変数を定義できません.           外部クラスの作用範囲の外側で内部クラスオブジェクトを作成するには、まず外部クラスオブジェクトを作成する必要があります.  (2)メソッド間で定義される静的内部クラス:       ●外部クラスの静的メンバーのみにアクセスできます.         静的内部クラスに外部への参照がありません  (3)メソッドで定義されたローカル内部クラス:       ●内部クラスにアクセス制御権限がない       ・周辺クラスにはメソッド内のローカル内部クラスは見えませんが、ローカル内部クラスは周辺クラスの任意のメンバーにアクセスできます.       ・メソッドボディではローカル内部クラスにアクセスできますが、アクセス文はローカル内部クラスを定義した後でなければなりません.       ・ローカル内部クラスは、メソッドボディの定数、すなわちfinalで修飾されたメンバーにのみアクセスできます.  (4)メソッドで定義された
(本編は個人転載整理)ご注目ありがとうございます!