匿名内部类不是子类吗?

时间:2018-08-17 23:25:45

标签: java anonymous-inner-class

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

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

在这种情况下,Obj是匿名内部类的实例,该内部类的toString方法已被覆盖。由于它是用类型A声明的,因此匿名类必须是A的子类。那么,为什么不将此类称为匿名子类而不是匿名内部类呢? “内在”来自哪里?

4 个答案:

答案 0 :(得分:4)

是的,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的子类...),但它也是一个匿名类。

答案 1 :(得分:3)

  

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

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

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

  • 因为人类是懒惰的 3 ,所以“匿名内部子类”是另外一个音节。换句话说,人们自然会优化他们的言语和写作方式。

  • 因为...约定。

  

“内部”来自哪里?

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

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

在@Andreas的答案中查看不错的分类法。


历史脚注。

实际上,官方术语是匿名类。实际上,早在Java 1.1中,当将构造添加到语言时,Sun就使用术语“匿名类”而不是“匿名内部类”。例如,Java 1.1.4发行说明中的​​"Inner Class Specification"经常将它们称为“匿名类”。

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


1-在琐碎的意义上除外。每个不是Object的类都必须是 some 类的子类。

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

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

答案 2 :(得分:2)

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

Java类是这样的类别, 1

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

分类未指定该类是子类,基类还是独立类。任何类别的类都可以是子类或基类。与ernest_k mentioned in another answer一样,可以从接口定义匿名类,在这种情况下,它根本不是子类。

1)在this other answer末尾摘录更大的层次结构。

答案 3 :(得分:1)

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

  

“由于声明了类型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);
    }
}

请记住,匿名类可以是“内部” OR “嵌套”。因此,通常在谈论它们时,只需说“匿名类”即可。 (匿名内部类是匿名类的一种)。另外,请务必阅读注释,因为它们会给出大多数解释。

有什么问题吗? :)