声明和实例化

  • 普通类:声明时具有一个名称,并且可以在任何地方多次实例化
class MyRunnable implements Runnable {
    public void run() {
        // Do something
    }
}

// 实例化
Runnable runnable = new MyRunnable();
```
  • 匿名类:在声明的同时进行实例化,没有名称,且只能使用一次。通常用于创建接口的实现或者是类的子类的对象。
Runnable runnable = new Runnable() {
    public void run() {
        // Do something
    }
};
```

作用域

  • 普通类:可以在它们被定义的整个包内(或更广泛地,如果它们是公共的)重复使用。
  • 匿名类:作用域局限于它们被声明的块内。

构造器

  • 普通类:可以有一个或多个构造器,并且可以有不同的参数列表。
  • 匿名类:没有构造器。匿名类不能定义任何“构造函数”。但可以通过实例初始化块来模拟构造器的效果,也可以使用超类的构造器。

访问局部变量

  • 普通类:不能直接访问定义它们的方法的局部变量,除非这些局部变量是final的或者是effectively final(即从本质上是final,即使没有被final修饰)。
  • 匿名类:同样受到这样的限制,它们可以访问外部方法的final或effectively final的局部变量。

Lambda表达式

  • 随着Java 8的引入,许多原本使用匿名类的场景都可以被Lambda表达式所取代,但Lambda表达式只能用于函数式接口的实现。

序列化

  • 普通类:如果实现了Serializable接口,则可以被序列化。
  • 匿名类:即使它们的超类可以被序列化,匿名类通常也不是为了序列化而设计的,因为它们没有稳定的类名称。

可读性和维护性

  • 普通类:通常更易于阅读和维护,因为它们有明确的名称和定义。
  • 匿名类:可能会使代码难以阅读,尤其是当匿名类很大或者有多个匿名类嵌套时。

使用场景

  • 普通类:适用于需要多次实例化,或者具有复杂行为的场景。
  • 匿名类:适合于简单的扩展或实现,尤其是当这种行为只需要一次时。

总的来说,匿名类适用于那些仅需要一次使用的实现,而普通类则适用于需要重复使用和可能需要更多逻辑的情况。随着Java 8的Lambda表达式和方法引用,可以以更简洁的方式来替代许多匿名类的使用。