在Java中匿名类有什么用?我们可以说使用匿名类是Java的优点之一吗?
当前回答
内部类与外部类的实例相关联,有两种特殊类型:局部类和匿名类。匿名类使我们能够同时声明和实例化一个类,从而使代码简洁。当我们只需要一个本地类一次时,我们使用它们,因为它们没有名字。
考虑一下文档中的例子,我们有一个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引入了一个术语函数接口,它是一个只有一个抽象方法的接口,因此我们可以说CheckPerson是一个函数接口。我们可以使用Lambda表达式,它允许我们将函数作为方法参数传递给:
printPersons(
roster,
(Person p) -> p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25
);
我们可以使用标准功能接口Predicate来代替接口CheckPerson,这将进一步减少所需的代码量。
其他回答
是的,匿名内部类绝对是Java的优势之一。
使用匿名内部类,您可以访问周围类的final变量和成员变量,这在侦听器等方面很方便。
但是一个主要的优点是,内部类代码(至少应该)与周围的类/方法/块紧密耦合,具有特定的上下文(周围的类、方法和块)。
您可以这样使用匿名类
TreeSet treeSetObj = new TreeSet(new Comparator()
{
public int compare(String i1,String i2)
{
return i2.compareTo(i1);
}
});
它们通常用作详细形式的回调。
我想你可以说,与没有它们和每次都必须创建命名类相比,它们是一个优势,但类似的概念在其他语言中实现得更好(如闭包或块)。
下面是一个swing的例子
myButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
// do stuff here...
}
});
尽管它仍然很冗长,但它比强迫您为每个throw away侦听器定义一个命名类要好得多(尽管这取决于情况和重用,这可能仍然是更好的方法)
匿名内部类用于以下场景:
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");
}
});
}
}
匿名内部类实际上是闭包,所以它们可以用来模拟lambda表达式或“委托”。以这个接口为例:
public interface F<A, B> {
B f(A a);
}
您可以匿名使用它在Java中创建一级函数。假设你有以下方法,返回给定列表中第一个比i大的数字,如果没有比i大的数字,则返回i:
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的一个很好的库:函数式Java。
推荐文章
- .toArray(new MyClass[0]) or .toArray(new MyClass[myList.size()])?
- Hibernate中不同的保存方法之间有什么区别?
- Java 8流和数组操作
- Java Regex捕获组
- Openssl不被视为内部或外部命令
- 如何添加自定义方法到Spring Data JPA
- 如何在Ubuntu中设置Java环境路径
- 无法执行dex:在Eclipse中超过GC开销限制
- 有人能解释一下JPA和Hibernate中的mappedBy吗?
- 是什么导致JNI调用变慢?
- Java中的&和&&有什么区别?
- 使用Java的Collections.singletonList()?
- Maven使用多个src目录编译
- 导入时无法解析符号
- 用谓词限制流