Javaでの匿名クラスの使用は何ですか? 匿名クラスの使用は、Java の利点の 1 つと言えますか?
18 に答える
「匿名クラス」とは、匿名の内部クラスを意味すると思います。
匿名の内部クラスは、実際にクラスをサブクラス化することなく、メソッドのオーバーライドなどの特定の「エクストラ」を使用してオブジェクトのインスタンスを作成するときに役立ちます。
私はこれをイベントリスナーをアタッチするためのショートカットとして使用する傾向があります。
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// do something
}
});
このメソッドを使用すると、実装する追加のクラスを作成する必要がないため、コーディングが少し速くなりActionListener
ます。実際に別のクラスを作成しなくても、匿名の内部クラスをインスタンス化できます。
このテクニックは、クラス全体を作成する必要がないと感じる「迅速で汚い」タスクにのみ使用します。まったく同じことを行う複数の匿名内部クラスがある場合は、内部クラスであろうと別のクラスであろうと、実際のクラスにリファクタリングする必要があります。
匿名の内部クラスは効果的にクロージャであるため、ラムダ式または「デリゲート」をエミュレートするために使用できます。たとえば、次のインターフェイスを使用します。
public interface F<A, B> {
B f(A a);
}
これを匿名で使用して、Java でファーストクラスの関数を作成できます。指定されたリストで i より大きい最初の数値を返す次のメソッドがあるとします。または、それより大きい数値がない場合は i を返します。
public static int larger(final List<Integer> ns, final int i) {
for (Integer n : ns)
if (n > i)
return n;
return i;
}
そして、指定されたリストの i より小さい最初の数値を返す別のメソッドがあります。小さい数値がない場合は i を返します。
public static int smaller(final List<Integer> ns, final int i) {
for (Integer n : ns)
if (n < i)
return n;
return i;
}
これらの方法はほとんど同じです。ファーストクラスの関数型 F を使用して、これらを次のように 1 つのメソッドに書き換えることができます。
public static <T> T firstMatch(final List<T> ts, final F<T, Boolean> f, T z) {
for (T t : ts)
if (f.f(t))
return t;
return z;
}
匿名クラスを使用して firstMatch メソッドを使用できます。
F<Integer, Boolean> greaterThanTen = new F<Integer, Boolean> {
Boolean f(final Integer n) {
return n > 10;
}
};
int moreThanMyFingersCanCount = firstMatch(xs, greaterThanTen, x);
これは非常に不自然な例ですが、関数を値であるかのように渡すことができることは、非常に便利な機能であることが簡単にわかります。Joel 自身による「Can Your Programming Language Do This」を参照してください。
このスタイルで Java をプログラミングするための優れたライブラリー: Functional Java。
I use them sometimes as a syntax hack for Map instantiation:
Map map = new HashMap() {{
put("key", "value");
}};
vs
Map map = new HashMap();
map.put("key", "value");
It saves some redundancy when doing a lot of put statements. However, I have also run into problems doing this when the outer class needs to be serialized via remoting.
これらは通常、詳細な形式のコールバックとして使用されます。
それらがなく、毎回名前付きクラスを作成する必要がある場合と比較して、それらは利点であると言えると思いますが、同様の概念は他の言語(クロージャまたはブロックとして)ではるかに優れて実装されています
これがスイングの例です
myButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
// do stuff here...
}
});
それでも厄介な冗長性がありますが、このようにすべての破棄リスナーに対して名前付きクラスを定義するように強制するよりもはるかに優れています(ただし、状況と再利用によっては、それでもより良いアプローチになる可能性があります)
別の関数内で特定の目的のためにクラスを作成する必要がある状況で使用します。たとえば、リスナーとして、ランナブルとして(スレッドを生成するため)などです。
関数のコード内から呼び出すので、他の場所で参照することはないので、名前を付ける必要はありません。コンパイラはそれらを列挙するだけです。
それらは本質的に構文糖衣であり、大きくなるにつれて一般的に他の場所に移動する必要があります。
それがJavaの利点の1つであるかどうかはわかりませんが、Javaを使用する場合(残念ながら、私たち全員が頻繁に使用します)、Javaの利点の1つであると主張することができます。
匿名クラスのガイドライン。
匿名クラスは宣言と初期化が同時に行われます。
匿名クラスは、ただ 1 つのクラスまたはインターフェイス resp に拡張または実装する必要があります。
匿名クラスには名前がないため、一度しか使用できません。
例えば:
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
});
new Thread() {
public void run() {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
System.out.println("Exception message: " + e.getMessage());
System.out.println("Exception cause: " + e.getCause());
}
}
}.start();
これは、スレッドを使用した匿名内部タイプの例の1つでもあります。
はい、匿名内部クラスは間違いなく Java の利点の 1 つです。
匿名の内部クラスを使用すると、周囲のクラスの final 変数とメンバー変数にアクセスでき、リスナーなどで役立ちます。
しかし、主な利点は、(少なくともそうあるべきである) 周囲のクラス/メソッド/ブロックに緊密に結合されている内部クラス コードが、特定のコンテキスト (周囲のクラス、メソッド、およびブロック) を持っていることです。
内部クラスは外部クラスのインスタンスに関連付けられており、ローカル クラスと匿名クラスの 2 つの特別な種類があります。匿名クラスを使用すると、クラスの宣言とインスタンス化を同時に行うことができるため、コードが簡潔になります。名前がないため、ローカル クラスが 1 回だけ必要な場合に使用します。
クラスがあるdocの例を考えてみましょう:Person
public class Person {
public enum Sex {
MALE, FEMALE
}
String name;
LocalDate birthday;
Sex gender;
String emailAddress;
public int getAge() {
// ...
}
public void printPerson() {
// ...
}
}
また、検索条件に一致するメンバーを次のように出力するメソッドがあります。
public static void printPersons(
List<Person> roster, CheckPerson tester) {
for (Person p : roster) {
if (tester.test(p)) {
p.printPerson();
}
}
}
どこCheckPerson
に次のようなインターフェースがあります:
interface CheckPerson {
boolean test(Person p);
}
これで、このインターフェースを実装する匿名クラスを利用して、検索基準を次のように指定できます。
printPersons(
roster,
new CheckPerson() {
public boolean test(Person p) {
return p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25;
}
}
);
ここでは、インターフェースは非常に単純で、無名クラスの構文は扱いにくく不明確に見えます。
Java 8では、抽象メソッドが 1 つしかないインターフェースである機能インターフェースという用語が導入されたため、機能インターフェースと言えCheckPerson
ます。関数をメソッド引数として次のように渡すことができるラムダ式を利用できます。
printPersons(
roster,
(Person p) -> p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25
);
Predicate
インターフェイスの代わりに標準の関数型インターフェイスを使用できますCheckPerson
。これにより、必要なコードの量がさらに削減されます。
新しいスレッドを呼び出すために匿名オブジェクトを使用します..
new Thread(new Runnable() {
public void run() {
// you code
}
}).start();
ファイナライザー ガーディアンを呼び出すクラス ファイナライズでの匿名クラスの主な使用法の 1 つ。Java の世界では、ファイナライズ メソッドの使用は、本当に必要になるまで避けるべきです。スーパー クラスの finalize メソッドは自動的に呼び出されず、メモリ リークの問題が発生する可能性があるため、サブクラスの finalize メソッドをオーバーライドするときは、常にsuper.finalize()
同様に呼び出す必要があることを覚えておく必要があります。
上記の事実を考慮すると、次のような匿名クラスを使用できます。
public class HeavyClass{
private final Object finalizerGuardian = new Object() {
@Override
protected void finalize() throws Throwable{
//Finalize outer HeavyClass object
}
};
}
この手法を使用すると、自分自身と他の開発者が、ファイナライズ メソッドを必要とするsuper.finalize()
の各サブクラスを呼び出す必要がなくなります。HeavyClass
Anonymous Inner Classは、二度と参照されないオブジェクトを作成するために使用されます。名前はなく、同じステートメントで宣言および作成されます。これは、オブジェクトの変数を通常使用する場所で使用されます。new
変数をキーワード、コンストラクターの呼び出し、 and 内のクラス定義に{
置き換えます}
。
Java でスレッド化されたプログラムを作成する場合、通常は次のようになります。
ThreadClass task = new ThreadClass();
Thread runner = new Thread(task);
runner.start();
ここThreadClass
で使用される はユーザー定義です。このクラスは、Runnable
スレッドの作成に必要なインターフェースを実装します。メソッド内 ( 内のメソッドのみ)も実装する必要がありますThreadClass
。取り除く方がより効率的であることは明らかであり、それがまさに匿名内部クラスが存在する理由です。run()
Runnable
ThreadClass
次のコードを見てください
Thread runner = new Thread(new Runnable() {
public void run() {
//Thread does it's work here
}
});
runner.start();
task
このコードは、一番上の例で行われた参照を置き換えます。別のクラスを持つのではなく、コンストラクター内の匿名内部クラスは、インターフェイスを実装し、メソッドをオーバーライドThread()
する名前のないオブジェクトを返します。メソッドには、スレッドに必要な作業を行うステートメントが内部に含まれます。Runnable
run()
run()
Anonymous Inner Classes が Java の利点の 1 つであるかどうかという質問に答えると、現時点では多くのプログラミング言語に精通していないため、確信が持てないと言わざるを得ません。しかし、私が言えることは、それは間違いなくより迅速で簡単なコーディング方法であるということです.
参考文献: Sams が 21 日間で Java を独学する 第 7 版