在Java中匿名类有什么用?我们可以说使用匿名类是Java的优点之一吗?


当前回答

您可以在需要在另一个函数中为特定目的创建类的情况下使用它,例如,作为侦听器,作为可运行对象(生成线程)等。

其思想是,从函数代码内部调用它们,因此永远不会在其他地方引用它们,因此不需要命名它们。编译器只是枚举它们。

它们本质上是语法糖,当它们变大时通常应该转移到其他地方。

我不确定这是否是Java的优点之一,但如果您确实使用它们(不幸的是,我们都经常使用它们),那么您可能会认为它们是优点之一。

其他回答

优化代码的最佳方法。也可以用于类或接口的重写方法。

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();
    }

}

内部类与外部类的实例相关联,有两种特殊类型:局部类和匿名类。匿名类使我们能够同时声明和实例化一个类,从而使代码简洁。当我们只需要一个本地类一次时,我们使用它们,因为它们没有名字。

考虑一下文档中的例子,我们有一个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,这将进一步减少所需的代码量。

匿名内部类用于创建一个永远不会被再次引用的对象。它没有名称,在同一个语句中声明和创建。 这用于通常使用对象变量的地方。用new关键字替换变量,调用构造函数和{and}内的类定义。

当用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();

这段代码替换了最上面的示例中对任务的引用。Thread()构造函数中的匿名内部类并没有单独的类,而是返回一个未命名的对象,该对象实现了Runnable接口并重写了run()方法。方法run()将包含执行线程所需工作的语句。

在回答“匿名内部类是否是Java的优点之一”这个问题时,我不得不说我不太确定,因为目前我对许多编程语言都不熟悉。但我能说的是,这绝对是一种更快更简单的编码方法。

参考资料:山姆自学Java在21天第七版

它们通常用作详细形式的回调。

我想你可以说,与没有它们和每次都必须创建命名类相比,它们是一个优势,但类似的概念在其他语言中实现得更好(如闭包或块)。

下面是一个swing的例子

myButton.addActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent e) {
        // do stuff here...
    }
});

尽管它仍然很冗长,但它比强迫您为每个throw away侦听器定义一个命名类要好得多(尽管这取决于情况和重用,这可能仍然是更好的方法)

匿名类在类终结中的主要用法之一叫做终结器守护者。在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
        }
    };
}

使用这种技术,您可以让自己和其他开发人员在需要finalize方法的重量级类的每个子类上调用super.finalize()。