Javaの改善編 - 内部クラスの詳細説明では、匿名内部クラスについて簡単に紹介していますが、内部クラスには他にも細かい問題がまだたくさんあるため、このブログが派生しました。このブログでは、匿名内部クラスの使用法、匿名内部クラスで注意すべきこと、匿名内部クラスを初期化する方法、および匿名内部クラスで使用される仮パラメータが Final でなければならない理由について学ぶことができます。
1. 匿名内部クラスを使用する 内部クラス
匿名内部クラスには名前がないため、作成方法が少し奇妙です。作成形式は次のとおりです:
new 父类构造器(参数列表)|实现接口() { //匿名内部类的类体部分 }
ここで、匿名内部クラスを使用するには、親クラスを継承するか、インターフェイスを実装する必要があることがわかります。 もちろん、親クラスを継承するか、インターフェイスを実装できるのは 1 つだけです。同時に、匿名内部クラスは new を直接使用してオブジェクトへの参照を生成するため、class キーワードがありません。もちろん、この参照は暗黙的です。
public abstract class Bird { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public abstract int fly(); } public class Test { public void test(Bird bird){ System.out.println(bird.getName() + "能够飞 " + bird.fly() + "米"); } public static void main(String[] args) { Test test = new Test(); test.test(new Bird() { public int fly() { return 10000; } public String getName() { return "大雁"; } }); } } ------------------ Output: 大雁能够飞 10000米
Test クラスでは、test() メソッドは Bird 型パラメータを受け入れますが、同時に、抽象クラスを直接新規作成する方法がないこともわかっています。その前に、まず実装クラスを作成する必要があります。実装クラスのインスタンス。したがって、メイン メソッドで匿名内部クラスを直接使用して、Bird インスタンスを作成します。
匿名内部クラスは抽象クラスになることができないため、その抽象親クラスまたはインターフェイスにすべての抽象メソッドを実装する必要があります。名前 この匿名内部コードは、実際には次の形式に分割できます:
public class WildGoose extends Bird{ public int fly() { return 10000; } public String getName() { return "大雁"; } } WildGoose wildGoose = new WildGoose(); test.test(wildGoose);
ここで、システムは Bird クラスから匿名クラスを継承するオブジェクトを作成し、それが Bird 型への参照に変換されます。
匿名内部クラスの使用には欠陥があります。つまり、匿名内部クラスを作成すると、すぐにクラスのインスタンスが作成され、クラスの定義がすぐに消えてしまいます。 , そのため、匿名内部クラスを再利用することはできません。上記の例では、test() メソッドで内部クラスを複数回使用する必要がある場合は、匿名内部クラスを使用する代わりにクラスを再定義することをお勧めします。
2. 注意事項
匿名内部クラスを使用する際には、以下の点に注意する必要があります。
1. 匿名内部クラスを使用する場合、クラスを継承したり、インターフェースを実装したりする必要がありますが、両方 両方を持つことはできず、1 つのクラスを継承するか、1 つのインターフェイスのみを実装できます。
2. 匿名内部クラスではコンストラクターを定義できません。
3. 匿名内部クラスには静的メンバー変数と静的メソッドを含めることはできません。
4. 匿名内部クラスはローカル内部クラスであるため、ローカル内部クラスに対するすべての制限は匿名内部クラスにも適用されます。
5. 匿名内部クラスは、継承されたクラスまたは実装されたインターフェイスのすべての抽象メソッドを実装する必要があります。
3. 使用する仮パラメータをfinalにする必要があるのはなぜですか
匿名の内部クラスにパラメータを渡すとき、内部クラスで仮パラメータを使用する必要がある場合、仮パラメータはfinalでなければなりません。つまり、メソッドの仮パラメータを内部クラスで使用する必要がある場合、仮パラメータはfinalでなければなりません。
なぜ最終的なものでなければならないのですか?
まず、内部クラスが正常にコンパイルされた後、クラス ファイルが生成されることがわかります。このクラス ファイルは外部クラスと同じクラス ファイルではなく、外部クラスへの参照のみを保持します。外部クラスによって渡されたパラメータを内部クラスによって呼び出す必要がある場合、Java プログラムの観点からは、それらは直接呼び出されます:
public class OuterClass { public void display(final String name,String age){ class InnerClass{ void display(){ System.out.println(name); } } } }
上記のコードから、name パラメータは次のように直接呼び出される必要があるように見えます。内部クラス?実際にはそうではありません。Java コンパイル後の実際の動作は次のとおりです:
public class OuterClass$InnerClass { public InnerClass(String name,String age){ this.InnerClass$name = name; this.InnerClass$age = age; } public void display(){ System.out.println(this.InnerClass$name + "----" + this.InnerClass$age ); } }
したがって、上記のコードから判断すると、内部クラスはメソッドによって渡されたパラメーターを直接呼び出すのではなく、独自のコンストラクターを使用してバックします。メソッドが実際に呼び出すのは、外部メソッドによって渡されたパラメーターではなく、メソッド自体のプロパティです。
直到这里还没有解释为什么是final?在内部类中的属性和外部方法的参数两者从外表上看是同一个东西,但实际上却不是,所以他们两者是可以任意变化的,也就是说在内部类中我对属性的改变并不会影响到外部的形参,而然这从程序员的角度来看这是不可行的,毕竟站在程序的角度来看这两个根本就是同一个,如果内部类该变了,而外部方法的形参却没有改变这是难以理解和不可接受的,所以为了保持参数的一致性,就规定使用final来避免形参的不改变。
简单理解就是,拷贝引用,为了避免引用值发生改变,例如被外部类的方法修改等,而导致内部类得到的值不一致,于是用final来让该引用不可改变。
故如果定义了一个匿名内部类,并且希望它使用一个其外部定义的参数,那么编译器会要求该参数引用是final的。
四、匿名内部类初始化
我们一般都是利用构造器来完成某个实例的初始化工作的,但是匿名内部类是没有构造器的!那怎么来初始化匿名内部类呢?使用构造代码块!利用构造代码块能够达到为匿名内部类创建一个构造器的效果。
public class OutClass { public InnerClass getInnerClass(final int age,final String name){ return new InnerClass() { int age_ ; String name_; //构造代码块完成初始化工作 { if(0 < age && age < 200){ age_ = age; name_ = name; } } public String getName() { return name_; } public int getAge() { return age_; } }; } public static void main(String[] args) { OutClass out = new OutClass(); InnerClass inner_1 = out.getInnerClass(201, "chenssy"); System.out.println(inner_1.getName()); InnerClass inner_2 = out.getInnerClass(23, "chenssy"); System.out.println(inner_2.getName()); } }
更多详解匿名内部类相关文章请关注PHP中文网!