实例化抽象 class 时发生了什么?什么是匿名内部class?

What is happening while instantiating an abstract class? What is an anonymous inner class?

实例化 class 人物时发生了什么?什么是匿名内部 class?

abstract class Person {
    abstract void eat();
}

class TestAnonymousInner {
    public static void main(String args[]) {
        Person p = new Person() {
            void eat() {
                System.out.println("nice fruits");
            } // what happens here?
        };
        p.eat();
    }
}  

Personabstract 所以你不能实例化它;但是通过在实例化期间为 abstract 方法注入一个实现, Person 变成 "instantiatable" ;最后调用 eat(),结果将是:eat() => nice fruits

匿名 classes 实际上只是语法糖。

由于 Person 是抽象的,您不能直接创建 Person 的实例。您必须创建一个继承 Person 的 class 的实例。这就是抽象 classes 的设计方式。

然而,有时当您想使用此 class 时,创建 Person 的子 class 非常不方便。你必须这样写:

class MyClass {
    public static void main(String args[]) {
        Person p = new PersonSubclass();
        p.eat();
    }
}  

class PersonSubclass extends Person {
    void eat() {
       System.out.println("nice fruits");
    }
}

阅读您的代码的人必须找到 PersonSubclass 的声明才能了解代码的作用。

但是我们想一想问题的根源:之所以不能创建Person的实例是因为eat没有方法体。因此,如果您为 eat 创建方法体,则可以 "kind of" 创建 Person 的实例。这就是匿名 classes。它们允许您仅通过编写方法主体来创建抽象 classes/interfaces 的实例。所以上面的代码只能这样写:

public static void main(String args[]) {
    Person p = new Person() {
        void eat() {
            System.out.println("nice fruits");
        }
    };
    p.eat();
}

它更短更容易阅读,不是吗?

那么这里到底发生了什么?

编译器为您创建 Person 的子 class,作为封闭 class 的内部 class。在那个子 class 中,有 eat 的方法体。内部 class 被赋予了一个非常特殊的名称(虽然我不记得是什么),因此普通代码无法访问它。

P.S。在 Java 8 中,引入了 lambda。它们又是只有一种方法的接口的语法糖。不过,这不适用于抽象 classes。

其实Anonymous Inner class就是声明实例化的方式class 同时。除了没有名字外,它们与任何其他 classes 一样。每当你声明一个 Inner class 无论它是 Anonymous 与否,编译器都会为那个 class。就像这里发生的事情一样,编译器创建了一个内部 class 如下

static class TestAnonymousInner extends Person  
{  
   TestAnonymousInner(){}  
   void eat()  
    {  
        System.out.println("nice fruits");  
    }  
} 

您可以看到这与任何其他本地 classes 一样。但是由于 Person 是一个 abstract class,它不能在不扩展的情况下被实例化。这就是为什么编译器创建的内部 class 是类型 extends Person