这真的可能吗?
这真的可能吗?
如果你指的是匿名函数,并且使用的是Java 8之前的版本,那么简而言之,不行。(如果你使用Java 8+,请阅读有关lambda表达式的文章)
然而,你可以实现一个带有函数的接口,如下所示:
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!"
这段代码并不是非常有用,但它展示了如何创建一个继承自Object
且覆盖 toString()
方法的匿名内部类的实例。
当需要实现一个可能不太可重用(因此不值得重新设计为自己命名的类)的接口
时,匿名内部类非常方便。一个有启发性的例子是使用自定义java.util.Comparator<T>
进行排序。
下面是一个示例,演示如何根据String.length()
对String[]
进行排序。
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中引入了Lambda表达式,您现在可以使用匿名方法。
假设我有一个名为Alpha
的类,我想按特定条件过滤Alpha
。为此,您可以使用Predicate<Alpha>
。这是一个功能接口,它有一个接受Alpha
并返回boolean
的test
方法。
假设filter方法具有以下签名:
List<Alpha> filter(Predicate<Alpha> filterPredicate)
使用旧的匿名类解决方案,你需要像这样做:
filter(new Predicate<Alpha>() {
boolean test(Alpha alpha) {
return alpha.centauri > 1;
}
});
使用Java 8的lambda表达式,您可以做到:
filter(alpha -> alpha.centauri > 1);
更详细的信息请查看Lambda表达式教程
在其他答案中已经实现了使用匿名内部类来实现或扩展现有类型的接口,尽管值得注意的是,可以实现多个方法(通常使用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
而不是cur
在print
方法中编写此内容。 拒绝捕获“隐式final
”局部变量?
node
为 final
。 - BalusCcur
。 - Tom Hawtin - tackline是的,如果您正在使用Java 8或更高版本,则可以。Java 8使定义匿名函数成为可能,而在以前的版本中这是不可能的。
让我们从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。
括号,其中包含构造函数的参数,就像普通的类实例创建表达式一样。注意:当您实现一个接口时,没有构造函数,所以您使用一个空的括号,就像这个例子。
一个类声明体,其中允许方法声明但不允许语句。
您还可以根据需要使用Consumer
和BiConsumer
类型。 Consumer
接受一个参数,BiConsumer
接受两个参数。
public void myMethod() {
// you can declare it here
Consumer<String> myAnonymousMethod = s -> {
System.out.println(s);
};
// you can call it here
muAnonymousMethod.apply("Hello World");
}