それは可能ですか?
6 に答える
匿名関数を意味し、Java 8 より前のバージョンの Java を使用している場合は、一言で言えばノーです。( Java 8+ を使用している場合は、ラムダ式について読んでください)
ただし、次のような関数を使用してインターフェイスを実装できます。
Comparator<String> c = new Comparator<String>() {
int compare(String s, String s2) { ... }
};
これを内部クラスで使用して、ほぼ無名の関数を取得できます:)
匿名内部クラスの例を次に示します。
System.out.println(new Object() {
@Override public String toString() {
return "Hello world!";
}
}); // prints "Hello world!"
これはそのままではあまり役に立ちませんが、匿名内部クラスのインスタンスextends Object
と@Override
そのtoString()
メソッドを作成する方法を示しています。
こちらもご覧ください
interface
匿名の内部クラスは、再利用性が高くない可能性がある (したがって、独自の名前付きクラスにリファクタリングする価値がない)を実装する必要がある場合に非常に便利です。有益な例はjava.util.Comparator<T>
、並べ替えにカスタムを使用することです。
String[]
に基づいて をソートする方法の例を次に示しますString.length()
。
import java.util.*;
//...
String[] arr = { "xxx", "cd", "ab", "z" };
Arrays.sort(arr, new Comparator<String>() {
@Override public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
});
System.out.println(Arrays.toString(arr));
// prints "[z, cd, ab, xxx]"
ここで使用されている減算による比較のトリックに注意してください。この手法は一般的に壊れていると言わなければなりません: オーバーフローしないことが保証できる場合にのみ適用できます (String
長さの場合など)。
こちらもご覧ください
Java 8 でのラムダ式の導入により、匿名メソッドを使用できるようになりました。
クラスがあり、特定の条件で sAlpha
をフィルタリングしたいとします。Alpha
これを行うには、を使用できますPredicate<Alpha>
。test
これは、を受け取り、Alpha
を返すメソッドを持つ機能的なインターフェースboolean
です。
フィルター メソッドに次のシグネチャがあると仮定します。
List<Alpha> filter(Predicate<Alpha> filterPredicate)
古い匿名クラスのソリューションでは、次のようなことが必要になります。
filter(new Predicate<Alpha>() {
boolean test(Alpha alpha) {
return alpha.centauri > 1;
}
});
Java 8 ラムダを使用すると、次のことができます。
filter(alpha -> alpha.centauri > 1);
詳細については、ラムダ式のチュートリアルを参照してください。
既存の型のインターフェースを実装または拡張する匿名の内部クラスは、他の回答で行われていますが、複数のメソッドを実装できることに注意してください (たとえば、JavaBean スタイルのイベントを使用することが多い)。
少し認識されている機能として、匿名の内部クラスには名前がありませんが、型があります。インターフェイスに新しいメソッドを追加できます。これらのメソッドは、限られた場合にのみ呼び出すことができます。new
主に式自体とクラス内 (インスタンス初期化子を含む) に直接。初心者は混乱するかもしれませんが、再帰にとっては「興味深い」ものになる可能性があります。
private static String pretty(Node node) {
return "Node: " + new Object() {
String print(Node cur) {
return cur.isTerminal() ?
cur.name() :
("("+print(cur.left())+":"+print(cur.right())+")");
}
}.print(node);
}
(私は元々、メソッドnode
ではなく使用してこれを書きました。 「暗黙的に」ローカルをキャプチャすることに NO と答えますか? )cur
print
final
バージョン 8 の最新の Java を使用している場合は、はい。Java8 では、以前のバージョンでは不可能だった無名関数の定義が可能になります。
Java ドキュメントから例を挙げて、匿名関数、クラスを宣言する方法を理解しましょう
次の例、HelloWorldAnonymousClasses は、ローカル変数 frenchGreeting および spanishGreeting の初期化ステートメントで匿名クラスを使用しますが、変数englishGreeting の初期化にはローカル クラスを使用します。
public class HelloWorldAnonymousClasses {
interface HelloWorld {
public void greet();
public void greetSomeone(String someone);
}
public void sayHello() {
class EnglishGreeting implements HelloWorld {
String name = "world";
public void greet() {
greetSomeone("world");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Hello " + name);
}
}
HelloWorld englishGreeting = new EnglishGreeting();
HelloWorld frenchGreeting = new HelloWorld() {
String name = "tout le monde";
public void greet() {
greetSomeone("tout le monde");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Salut " + name);
}
};
HelloWorld spanishGreeting = new HelloWorld() {
String name = "mundo";
public void greet() {
greetSomeone("mundo");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Hola, " + name);
}
};
englishGreeting.greet();
frenchGreeting.greetSomeone("Fred");
spanishGreeting.greet();
}
public static void main(String... args) {
HelloWorldAnonymousClasses myApp =
new HelloWorldAnonymousClasses();
myApp.sayHello();
}
}
無名クラスの構文
frenchGreeting オブジェクトのインスタンス化を考えてみましょう:
HelloWorld frenchGreeting = new HelloWorld() {
String name = "tout le monde";
public void greet() {
greetSomeone("tout le monde");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Salut " + name);
}
};
匿名クラス式は、次のもので構成されます。
new
オペレーター_実装するインターフェースまたは拡張するクラスの名前。この例では、匿名クラスはインターフェース HelloWorld を実装しています。
通常のクラス インスタンス作成式と同様に、コンストラクタへの引数を含む括弧。注: インターフェイスを実装する場合、コンストラクターがないため、この例のように空の括弧のペアを使用します。
クラス宣言本体である本体。より具体的には、本文では、メソッド宣言は許可されていますが、ステートメントは許可されていません。