Listener などの実装に関しては、無名クラスがタイピングを節約することを知っています。それらは、クロージャーのいくつかの使用法の代わりになろうとします。
しかし、コミュニティはこの言語機能の価値についてどう考えているでしょうか? それは理にかなっており、定期的に使用していますか? コードがより明確になり、理解しやすくなり、保守しやすくなりますか? または、匿名クラスはコードを読みにくくしますか?
あなたの意見は?
Listener などの実装に関しては、無名クラスがタイピングを節約することを知っています。それらは、クロージャーのいくつかの使用法の代わりになろうとします。
しかし、コミュニティはこの言語機能の価値についてどう考えているでしょうか? それは理にかなっており、定期的に使用していますか? コードがより明確になり、理解しやすくなり、保守しやすくなりますか? または、匿名クラスはコードを読みにくくしますか?
あなたの意見は?
私は、何らかのタスクを実行するためだけに本格的なクラスを用意する必要がない状況で、匿名の内部クラスを使用する傾向があります。たとえば、ActionListener
orを実装したいRunnable
が、内部クラスを持つ必要はないと思います。たとえば、単純な を開始するにはThread
、匿名の内部クラスを使用する方が読みやすい場合があります。
public void someMethod()
{
new Thread(new Runnable() {
public void run()
{
// do stuff
}
}).start();
}
上記の例のような特定のケースでは、実行されるコードがすべて 1 つの場所に書かれているため、特に 1 回限りのタスクの場合、読みやすさが向上します。内部クラスを使用すると、コードが「非ローカライズ」されます。
public void someMethod()
{
new Thread(new MyRunnable()).start();
}
// ... several methods down ... //
class MyRunnable implements Runnable
{
public void run()
{
// do stuff
}
}
とはいえ、同じことが繰り返される場合は、通常のクラスであれ、内部クラスであれ、別のクラスにする必要があります。
私は、実際のアプリケーションの中心的な機能として使用するのではなく、試してみるだけのプログラムで匿名の内部クラスを使用する傾向があります。
匿名内部クラスのもう 1 つの有効な使用法は、ArrayList や Set などのコレクションを初期化する必要がある場合です。このプラクティスは、二重ブレースの初期化とも呼ばれます 。たとえば、
private static final Set<String> VALID_CODES = new HashSet<String>() {{
add("XZ13s");
add("AB21/X");
add("YYLEX");
add("AR2D");
}};
明らかに、これはコレクションに限定されません。任意の種類のオブジェクトを初期化するために使用できます。たとえば、Gui オブジェクト:
add(new JPanel() {{
setLayout(...);
setBorder(...);
add(new JLabel(...));
add(new JSpinner(...));
}});
私の意見では、匿名クラスはコードを読みにくくします。リスナーの実装には、匿名クラスが役立ちます。GWTアプリケーションを開発する場合は、匿名クラスの方が適しています。これらの場合、匿名クラスを使用していないと、コードの行数が増えます。
匿名クラスを定期的に使用します。メソッドが 1 つまたは 2 つしかなく、その機能が他のどこにも使用されていないインターフェイスを実装する場合に、これらは使いやすいと思います。同じ機能を別の場所で再度使用する場合は、再利用する実際のクラスが必要です。
匿名クラスを使用することで読みやすさが向上するか低下するかは好みの問題です。主な問題は間違いなくここではありません。
匿名クラスは、内部クラスと同様に、囲んでいるクラスへの参照を保持するため、それがなければ非公開のものになります。要するに、囲んでいるクラスのthis参照は、内部クラスを介してエスケープされる可能性があります。したがって、答えは次のとおりです。内部クラスがそれ自体を公開する場合、内部クラスを使用することは非常に悪い習慣です。例えば:
changeManager.register(new ChangeListener() {
public void onChange(...) {
...
}});
ここでは、匿名のChangeLstenerがChangeManagerのregisterメソッドに渡されます。そうすることで、外側のクラスも自動的に公開されます。
これは間違いなく悪い習慣です。
私はほとんどの場合、 RunnableやActionListenerなど、メソッドが 1 つしかないインターフェイスに匿名クラスを使用します。大規模なインターフェイスのほとんどは、独自のクラスまたは既存のクラスでの実装を保証します。それは私の意見なので、それを裏付ける議論は必要ありません。
匿名クラスは、主にイベント処理専用の GUI アプリケーションで見られます。匿名クラスは、1 つまたは 2 つのメソッドを含む小さなインターフェイスを実装する場合に役立ちます。たとえば、2 つまたは 3 つのスレッドを持つクラスがあり、これらのスレッドを使用して 2 つまたは 3 つの異なるタスクを実行します。この状況では、匿名クラスの助けを借りて目的のタスクを実行できます。次の例を見てください
class AnonymousClass{
public static void main(String args[]){
Runnable run1=new Runnable(){
public void run(){
System.out.println("from run1");
}
};
Runnable run2=new Runnable(){
public void run(){
System.out.println("from run2");
}
};
Runnable run3=new Runnable(){
public void run(){
System.out.println("from run3");
}
};
Thread t1=new Thread(run1);
Thread t2=new Thread(run2);
Thread t3=new Thread(run3);
t1.run();t2.run();t3.run();
}
}
出力:
run1 から
run2 から
run3 から
上記のコードのスナップでは、3 つのスレッドを使用して 3 つの異なるタスクを実行しています。3 つの異なる小さなタスクを実行する run メソッドの実装を含む 3 つの匿名クラスを作成しました。
スコープとアクセスを可能な限り制限することが良いことである場合、匿名クラスは非常に優れています。それらのスコープは、それらを必要とする 1 つのクラスに限定されます。それが適切な場合は、匿名クラスが良いと思います。
同じ機能を複製した瞬間、それは悪い考えになります。独立したパブリック クラスにリファクタリングします。リファクタリング機能を備えた IDE を使用すると、それが簡単になります。
何と比較するかによります。私はそれらを持っていないよりは持っていたいと思っていますが、compare() の実装を含むクラスを明示的に作成するよりも、Arrays.sort() のようなメソッドにプレーンなコード ブロックを提供できるようにしたいと考えています。
それらを使用することは理にかなっていますが、その下で行われていることに注意する必要があります。私は、他の場所では必要のない非常に具体的なことを行うクラスが必要な場合にのみ、それらを使用します。
匿名クラスには、本質的に異なるものや特別なものはありません。それらは最終的には、外部クラスの参照をサポートする単なる構文糖衣です。これにより、コレクション フレームワークによって返されるほとんどの Iterator 実装と同様に、アダプターの作成が容易になります。
一度だけ使用する場合、小さなインターフェイスに役立つという点で、他の多くの人が言っていることに同意します。ただし、匿名クラスの外部のコードを変更して機能させる必要がある場合は、匿名クラスを使用しないという制限も追加します。
anon クラスが変数を参照するため、anon クラスに対応するために変数を final として宣言する必要がある場合は、代わりに内部クラスを使用します。また、最終的な配列 (サイズ 1) を使用して anon クラスから結果を返すコードの悪臭も見てきました。
ほとんどの場合、匿名クラスを使用します a) インターフェースに 1 つまたは 2 つのメソッドがあり、読みやすさに影響しない場合は簡略表記
b)新しいクラスの作成を正当化できない状況。たとえば、簡単な操作のためにJButtonをさせるためにactionlistnerをアタッチする必要があるときのswing。