Javaでの匿名クラスの使用は何ですか?匿名クラスの使用がJavaの利点の1つであると言えますか?
Javaでの匿名クラスの使用は何ですか?匿名クラスの使用がJavaの利点の1つであると言えますか?
回答:
「匿名クラス」とは、匿名の内部クラスを意味するものと解釈します。
匿名内部クラスは、メソッドをオーバーライドするなど、特定の「エクストラ」を使用してオブジェクトのインスタンスを作成するときに、実際にクラスをサブクラス化する必要がない場合に役立ちます。
私はイベントリスナーをアタッチするためのショートカットとして使用する傾向があります。
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// do something
}
});
このメソッドを使用すると、実装する追加のクラスを作成する必要がないため、コーディングが少し速くなりActionListener
ます。実際に別のクラスを作成せずに、匿名の内部クラスをインスタンス化するだけで済みます。
このテクニックは、クラス全体を作成する必要がないと感じられる「迅速で汚い」タスクにのみ使用します。まったく同じことをする複数の匿名内部クラスを持つことは、それが内部クラスであろうと別のクラスであろうと、実際のクラスにリファクタリングされるべきです。
overloading methods
ではなくoverriding methods
?
匿名内部クラスは事実上クロージャであるため、ラムダ式または「デリゲート」をエミュレートするために使用できます。たとえば、次のインターフェイスを見てください。
public interface F<A, B> {
B f(A a);
}
これを匿名で使用して、Javaでファーストクラスの関数を作成できます。与えられたリストのiより大きい最初の数を返す次のメソッドがあるとしましょう。
public static int larger(final List<Integer> ns, final int i) {
for (Integer n : ns)
if (n > i)
return n;
return 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自身の「プログラミング言語でこれを実行できるか」を参照してください。
このスタイルでJavaをプログラミングするための素晴らしいライブラリ:関数型Java。
匿名の内部クラスは、次のシナリオで使用されます。
1.)オーバーライド(サブクラス化)の場合、クラス定義が現在のケース以外で使用できない場合:
class A{
public void methodA() {
System.out.println("methodA");
}
}
class B{
A a = new A() {
public void methodA() {
System.out.println("anonymous methodA");
}
};
}
2.)インターフェースを実装するために、現在の場合にのみインターフェースの実装が必要な場合:
interface interfaceA{
public void methodA();
}
class B{
interfaceA a = new interfaceA() {
public void methodA() {
System.out.println("anonymous methodA implementer");
}
};
}
3.)引数定義の匿名内部クラス:
interface Foo {
void methodFoo();
}
class B{
void do(Foo f) { }
}
class A{
void methodA() {
B b = new B();
b.do(new Foo() {
public void methodFoo() {
System.out.println("methodFoo");
}
});
}
}
私は時々それらをマップのインスタンス化のための構文ハックとして使用します:
Map map = new HashMap() {{
put("key", "value");
}};
対
Map map = new HashMap();
map.put("key", "value");
多くのputステートメントを実行するときに冗長性を節約します。ただし、リモーティングを介して外部クラスをシリアル化する必要がある場合にも、これを実行するときに問題が発生しました。
これらは、通常、詳細形式のコールバックとして使用されます。
それらがなく、毎回名前付きクラスを作成する必要があることと比較して、それらは利点であると言えるかもしれませんが、同様の概念が他の言語で(クロージャーまたはブロックとして)はるかによく実装されています
これがスイングの例です
myButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
// do stuff here...
}
});
それはまだ厄介な冗長ですが、このようなすべての使い捨てリスナーに対して名前付きクラスを定義するように強制するよりもはるかに優れています(状況と再利用によっては、より良いアプローチである可能性があります)。
myButton.addActionListener(e -> { /* do stuff here */})
またはよりmyButton.addActionListener(stuff)
簡潔になります。
匿名クラスのガイドライン。
匿名クラスは同時に宣言され、初期化されます。
匿名クラスは、1つだけのクラスまたはインターフェースに拡張または実装する必要があります。
匿名クラスには名前がないため、一度しか使用できません。
例えば:
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
});
ref.getClass().newInstance()
。
はい、匿名の内部クラスは間違いなくJavaの利点の1つです。
匿名の内部クラスを使用すると、周囲のクラスの最終変数とメンバー変数にアクセスでき、リスナーなどで便利です。
ただし、主な利点は、周囲のクラス/メソッド/ブロックに(少なくとも結合する必要がある)内部クラスコードが特定のコンテキスト(周囲のクラス、メソッド、ブロック)を持っていることです。
新しいスレッドを呼び出すために匿名オブジェクトを使用します。
new Thread(new Runnable() {
public void run() {
// you code
}
}).start();
内部クラスは、外側のクラスのインスタンスに関連付けられており、二つの特別な種類がある:ローカルクラスおよび匿名クラス。匿名クラスを使用すると、クラスの宣言とインスタンス化を同時に行うことができるため、コードが簡潔になります。名前がないため、ローカルクラスが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
。これにより、必要なコードの量がさらに削減されます。
匿名の内部クラスは、さまざまなオブジェクトにさまざまな実装を提供する際に役立ちます。ただし、プログラムの可読性に問題が生じるため、非常に慎重に使用する必要があります。
ファイナライザーガーディアンと呼ばれるクラスファイナライズでの匿名クラスの主な使用法の1つ。Javaの世界では、finalizeメソッドの使用は、本当に必要になるまで避けてください。サブクラスのfinalizeメソッドをオーバーライドするときsuper.finalize()
は、スーパークラスのfinalizeメソッドが自動的に呼び出されず、メモリリークが発生する可能性があるため、常に呼び出す必要があることを覚えておく必要があります。
したがって、上記の事実を考慮すると、次のような匿名クラスを使用できます。
public class HeavyClass{
private final Object finalizerGuardian = new Object() {
@Override
protected void finalize() throws Throwable{
//Finalize outer HeavyClass object
}
};
}
この手法を使用するとsuper.finalize()
、HeavyClass
finalizeメソッドを必要とするの各サブクラスを呼び出す必要がなくなり、自分自身と他の開発者を解放できました。
ここでは誰も言及していないようですが、匿名クラスを使用してジェネリック型引数を保持することもできます(通常は型消去のために失われます)。
public abstract class TypeHolder<T> {
private final Type type;
public TypeReference() {
// you may do do additional sanity checks here
final Type superClass = getClass().getGenericSuperclass();
this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
}
public final Type getType() {
return this.type;
}
}
このクラスを匿名でインスタンス化する場合
TypeHolder<List<String>, Map<Ineger, Long>> holder =
new TypeHolder<List<String>, Map<Ineger, Long>>() {};
そのようなholder
インスタンスには、渡された型の消去されていない定義が含まれます。
これはバリデータ/デシリアライザを構築するのに非常に便利です。また、リフレクションを使用してジェネリック型をインスタンス化することもできます(そのためnew T()
、パラメーター化された型で実行したい場合は、歓迎します!)。
コードを最適化する最良の方法。また、クラスまたはインターフェースのオーバーライドメソッドに使用できます。
import java.util.Scanner;
abstract class AnonymousInner {
abstract void sum();
}
class AnonymousInnerMain {
public static void main(String []k){
Scanner sn = new Scanner(System.in);
System.out.println("Enter two vlaues");
int a= Integer.parseInt(sn.nextLine());
int b= Integer.parseInt(sn.nextLine());
AnonymousInner ac = new AnonymousInner(){
void sum(){
int c= a+b;
System.out.println("Sum of two number is: "+c);
}
};
ac.sum();
}
}
アン匿名内部クラスは、再び参照されることはありませんオブジェクトを作成するために使用されます。名前はなく、同じステートメントで宣言および作成されます。これは、通常オブジェクトの変数を使用する場合に使用されます。あなたはで変数を置き換えるnew
キーワード、コンストラクタの呼び出しとクラス定義の内側{
と}
。
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()
は、スレッドに必要な作業を実行するステートメントが含まれます。
匿名の内部クラスがJavaの利点の1つであるかどうかという質問に答えると、現時点では多くのプログラミング言語に精通していないので、よくわからないでしょう。しかし、私が言えることは、それは間違いなくコーディングのより迅速で簡単な方法です。
参考資料:Sams Teach Yourself Java in 21 Days Seventh Edition