繁体   English   中英

匿名内部类实际上不是子类吗?

[英]Aren't Anonymous Inner Classes actually subclasses?

假设 A 是一个自定义类,并考虑以下匿名内部类的声明:

A Obj = new A() {
    @Override
    public String toString() {
        return "Hello!";
    }
}

在这种情况下,Obj 是一个匿名内部类的实例,其 toString 方法已被覆盖。 既然是用类型A声明的,那么匿名类一定是A的子类。那么,为什么这个类不称为匿名子类而不是匿名内部类呢? “内在”从何而来?

是的, objA的子类的实例。 您可以通过调用obj.getClass().getSuperclass()来验证超类:

这会打印如下内容:

class stackoverflow.Test$1 //obj.getClass()
class stackoverflow.A //obj.getClass().getSuperclass()

那么,为什么这个类不称为匿名子类而不是匿名内部类呢?

这些只是语义。 这是一个名字。 然而,可能有很多原因,其中之一是匿名类可以直接实现接口:

Runnable r = new Runnable() {
    public void run() {}
}

这不是任何东西的子类(而是 Object,但什么不是 Object 的子类......),但它也是一个匿名类。

子类和内部类是匿名类的两个不同方面 由于语法,匿名类显然是命名类的子类,因此内部方面与分类更相关。

Java 类是这样的类别1

如您所见,匿名类是内部嵌套类。

分类不指定类是子类、基类还是独立类。 任何类别的类都可以是子类或基类。 正如ernest_k 在另一个答案中提到的,可以从接口定义匿名类,在这种情况下,它根本不是子类。

1)在另一个答案的末尾摘录更大的层次结构。

为什么这个类不称为匿名子类而不是匿名内部类?

  • 因为(通常)匿名内部类不一定是子类1 匿名内部类可以扩展接口而不是类。

  • 因为在我们谈论匿名内部类的大多数情况下,“子类性”并不重要2

  • 因为人类是懒惰的3并且“匿名内部子类”是一个额外的音节。 或者换句话说,人们有一种自然的倾向来优化他们的演讲和写作模式。

  • 因为……约定俗成。

“内在”从何而来?

Inner 在 Java 中具有技术含义。 这意味着两件事。

  • 这意味着该类是在另一个类中声明的。
  • 这意味着允许该类引用封闭类的实例的this

请参阅@Andreas 的回答中的不错的分类法。


历史脚注。

事实上,官方术语是匿名类。 事实上,Sun 在 Java 1.1 中使用术语“匿名类”而不是“匿名内部类”,当时该构造被添加到语言中。 例如,Java 1.1.4 发行说明中的“内部类规范”将它们称为“匿名类”……大多数情况下。

我怀疑发生的事情是 Sun 早期的演讲或论文中存在一些不一致之处,并且许多非 Sun 的作者在他们的作品中都使用了“匿名内部阶级”版本。 Sun 团队试图通过使用官方 Java 语言规范和教程中的“匿名类”来悄悄地纠正这个问题。 但为时已晚。 书在书店,文章在网上。


1 - 除了微不足道的意义。 这不是Object每个类必须有一些类的子类。

2 - 同样,您通常会说“我要带狗散步”,而不是“我要带黑色拉布拉多犬散步”。

3 - 在这种情况下,“好懒惰”。

要回答您的问题的标题,是的,它们是。 匿名内部类实际上是子类。

“由于它是用类型 A 声明的,匿名类 [Obj] 必须是 A 的子类。”

做得好。 :)

无论如何,要回答为什么存在“内部”:如果您在另一个类中声明一个匿名类(并且匿名类不是静态声明的,更多内容见下文),那么它将能够像访问它一样访问其周围的类内部类会。 例如:

public class Outer {
    private final int someRandomValue = 4;

    public final Object anonymousInnerInstance = new Object() {
        @Override
        public String toString() {
            // Notice how this class has access to a field declared inside a different
            // class. More specifically, this anonymous class can access someRandomValue,
            // even though someRandomValue belongs to the class, Outer.
            return "Anonymous Inner Class: " + someRandomValue;
        }
    };

    public class RegularInner {
        @Override
        public String toString() {
            // This regular inner class is inside Outer, (just like the anonymous class),
            // and can access any of Outer's fields (amongst Outer's other things).
            return "Regular Inner Class: " + someRandomValue;
        }
    }

    public final RegularInner regularInnerInstance = new RegularInner();

    public static void main(String[] args) {
        Outer outerInstance = new Outer();
        System.out.println(outerInstance.anonymousInnerInstance);
        System.out.println(outerInstance.regularInnerInstance);

        // By the way, you can make new RegularInner instances off of our Outer
        // instance:
        RegularInner newInnerInstance = outerInstance.new RegularInner();
        // When you write "outerInstance.new SomeClass()" you're saying:
        // "I'd like to initialize my 'SomeClass' object with 'outerInstance',
        // as its container." This effectively means that any variables that
        // belong to Outer that your SomeClass needs to access, it will access
        // from the Outer instance you gave it.
    }
}

因此, anonymousInnerInstance的底层类和类RegularInner都可以访问Outer的字段,以及属于Outer其他特定于实例的内容。 这就是匿名类有时可能被称为“内部”类的原因。

内部类的任何实例都需要使用外部类的实例来创建以支持它,否则它将不知道它属于哪个对象(不是类)。


静电垃圾

如果匿名类被声明为static ,它将无法访问其周围类的内容,也不会是“内部”类(相反,它将是匿名“嵌套”类)。

public class Outer {
    private final int someRandomValue = 4;

    public static final Object anonymousStaticInstance = new Object() {
        @Override
        public String toString() {
            // someRandomValue belongs to an INSTANCE of Outer. (So each Outer object you
            // have has its own someRandomValue). Since this anonymous class
            // is now static, it is no longer tied to an instance of Outer. It doesn't have
            // an Outer object that it can read "someRandomValue" from. The same goes for
            // RegularStatic, below.
            return "Anonymous Inner Class: " + someRandomValue;
        }
    };

    public static class RegularStatic {
        @Override
        public String toString() {
            return "Regular Inner Class: " + someRandomValue;
        }
    }

    public final RegularStatic regularInnerInstance = new RegularStatic();

    public static void main(String[] args) {
        Outer outerInstance = new Outer();
        System.out.println(outerInstance.anonymousStaticInstance);// Java warns you here and
        // tells you to access anonymousStaticInstance statically. This is because
        // anonymousStaticInstance no longer belongs to any given instance of Outer.
        // There is only one anonymousStaticInstance, that "belongs" to the class Outer,
        // rather than multiple anonymousInnerInstances which each belong to an instance
        // of Outer.
        System.out.println(outerInstance.regularInnerInstance);
    }
}

请记住,匿名类可以是“内部”“嵌套”的。 因此,当一般谈论它们时,只需说“匿名类”。 匿名内部类是一种匿名类)。 另外,请务必阅读评论,因为它们给出了大部分解释。

任何问题? :)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM