通过"匿名类",我认为你指的是匿名内部类。
当需要创建一个带有某些“附加功能”的对象实例(例如重写方法),而不必实际子类化类时,可以使用匿名内部类。
我倾向于将其用作快捷方式来附加事件监听器:
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// do something
}
});
使用这种方法可以使编码稍微快一点,因为我不需要制作一个实现ActionListener的额外类 - 我只需实例化一个匿名内部类而不实际制作一个单独的类。我仅在执行“快速且简单”的任务时使用此技术,在这种情况下,制作整个类似乎是不必要的。具有执行完全相同操作的多个匿名内部类应重构为实际类,无论是内部类还是单独类。匿名内部类实际上是闭包,因此它们可以用来模拟lambda表达式或“委托”。例如,考虑以下接口:
public interface F<A, B> {
B f(A a);
}
public static int larger(final List<Integer> ns, final int i) {
for (Integer n : ns)
if (n > i)
return n;
return i;
}
然后你还有另一种方法,返回给定列表中小于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,我们可以将它们重写为一个方法,如下所示:
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编程库可以用这种风格:Functional 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 map = new HashMap() {{
put("key", "value");
}};
vsMap map = new HashMap();
map.put("key", "value");
在进行许多put语句时,这可以节省一些重复性工作。但是,当外部类需要通过远程传输进行序列化时,我也遇到了问题。
它们通常被用作冗长的回调形式。
我想你可以说相比没有它们并且每次都需要创建一个命名类,它们是一种优势,但是类似的概念在其他语言中实现得更好(例如作为闭包或块)
这里有一个swing示例
myButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
// do stuff here...
}
});
虽然还是有点杂乱冗长,但是这比你强制为每一个一次性的监听器定义一个命名类要好得多(尽管根据情况和重用情况,仍可能是更好的方法)
myButton.addActionListener(e -> { /* do stuff here */})
或者myButton.addActionListener(stuff)
这样的写法会更加简洁。 - Samuel Edwin Ward匿名类的指南。
匿名类同时声明和初始化。
匿名类必须扩展或实现一个且仅一个类或接口。
由于匿名类没有名称,因此只能使用一次。
例如:
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
});
ref.getClass().newInstance()
。 - icza是的,匿名内部类绝对是Java的优势之一。
使用匿名内部类,您可以访问周围类的final和成员变量,这在监听器等方面非常有用。
但一个主要的优点是,内部类代码(至少应该)与周围的类/方法/块紧密耦合,并具有特定的上下文(周围的类、方法和块)。
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();
一个内部类与外部类的实例相关联,有两种特殊类型:局部类和匿名类。匿名类使我们能够同时声明和实例化一个类,从而使代码更加简洁。当我们只需要一个局部类一次时,我们使用它们,因为它们没有名称。
考虑来自文档的示例,其中我们有一个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;
}
}
);
CheckPerson
是一个函数式接口。我们可以利用Lambda表达式,将函数作为方法参数传递:printPersons(
roster,
(Person p) -> p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25
);
Predicate
来替换接口CheckPerson
,这将进一步减少所需代码量。