实例化抽象 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();
}
}
Person
是 abstract
所以你不能实例化它;但是通过在实例化期间为 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
实例化 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();
}
}
Person
是 abstract
所以你不能实例化它;但是通过在实例化期间为 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