问题
Assume that A is a custom class, and consider the following declaration of an anonymous inner class:
A Obj = new A() {
@Override
public String toString() {
return "Hello!";
}
}
In this scenario, Obj is an instance of an anonymous inner class whose toString method has been overridden. Since it was declared with type A, the anonymous class must be a subclass of A. So then, why isn't this class called an Anonymous Subclass instead of an anonymous inner class? Where does the 'inner' come from?
回答1:
To answer your question's title, yes, they are. Anonymous inner classes are actually subclasses.
"Since it was declared with type A, the anonymous class, [Obj], must be a subclass of A."
Good job. :)
Anyways, to answer why the "inner" is there: If you declare an anonymous class inside another class (and the anonymous class isn't declared statically, more on that below) then it would be able to access its surrounding class just like an inner class would. For example:
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.
}
}
So, anonymousInnerInstance
's underlying class, and the class RegularInner
, both have access to Outer
's fields, and other instance-specific content belonging to Outer
. That's why an anonymous class may sometimes be called an "inner" class.
Any instance of an inner class needs to be created with an instance of an outer class to back it up, or it won't know which object, (not class), it belongs to.
Static Trash
If an anonymous class is declared as static
, it won't have access to its surrounding class's content and wouldn't be an "inner" class (instead, it would be an anonymous "nested" class).
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);
}
}
Remember that anonymous classes can be "inner" OR "nested". So when talking about them in general, just say "anonymous class". (Anonymous inner classes are a type of anonymous class). Also, do make sure to read the comments as they give most of the explanation.
Any questions? :)
回答2:
Yes, obj
is an instance of a subclass of A
. And you can verify the superclass by calling obj.getClass().getSuperclass()
:
That prints something like:
class stackoverflow.Test$1 //obj.getClass()
class stackoverflow.A //obj.getClass().getSuperclass()
So then, why isn't this class called an Anonymous Subclass instead of an anonymous inner class?
Those are just semantics. It's a name. There could be many reasons, however, one of which being that anonymous classes can implement interfaces directly:
Runnable r = new Runnable() {
public void run() {}
}
This is not a subclass of anything (but Object, but what isn't a subclass of Object...), but it's an anonymous class too.
回答3:
Why isn't this class called an Anonymous Subclass instead of an anonymous inner class?
Because (in general) anonymous inner class aren't necessarily subclasses1. An anonymous inner class can extend an interface rather than a class.
Because the "subclass-ness" is not important2 in most contexts where we talk about anonymous inner classes.
Because humans are lazy3 and "Anonymous Inner Subclasses" is one extra syllable. Or to put it another way, there is a natural tendency for people to optimize their speech and writing patterns.
Because ... convention.
Where does the 'inner' come from?
Inner has a technical meaning in Java. It means two things.
- It means that the class is declared inside another class.
- It means that the class is permitted to refer to the
this
of an instance of the enclosing class.
See the nice taxonomy in @Andreas's answer.
Historical footnote.
In fact, the official terminology is Anonymous Class. Indeed, Sun used the terminology "Anonymous Class" rather than "Anonymous Inner Class" way back in Java 1.1 when the construct was added to the language. For example, the "Inner Class Specification" from the Java 1.1.4 release notes refers to them as "Anonymous Classes" ... most of the time.
I suspect that what happened was that there was some inconsistency in earlier Sun presentations or papers, and various non-Sun authors latched onto the "anonymous inner class" version in their writings. The Sun team tried to quietly correct this by using "Anonymous Class" in the official Java Language Spec and Tutorial. But it was too late. The books were in the bookshops, the articles were on the web.
1 - Except in the trivial sense. Every class that isn't Object must be a subclass of some class.
2 - Likewise, you would normally say "I am taking the dog for a walk", not "I am taking the black Labrador for a walk".
3 - In this case, "good lazy".
回答4:
Subclass and inner class are two difference aspects of the anonymous class. Because of the syntax, an anonymous class is obviously a subclass of the named class, so the inner aspect is more relevant for the categorization.
Java classes are categories like this1:
- Top-Level class (§7.6)
- Nested class (§8.5, §9.5)
- Static Nested class
- Inner class (§8.1.3)
- Local class (§14.3)
- Anonymous class (§15.9.5)
As you can see, an anonymous class is an inner nested class.
The categorization doesn't specify whether the class is a subclass, a base class, or a standalone class. Classes of any category can be a subclass or base class. As ernest_k mentioned in another answer, an anonymous class may be defined from an interface, in which case it's not a subclass at all.
1) Excerpt of bigger hierarchy at end of this other answer.
来源:https://stackoverflow.com/questions/51903919/arent-anonymous-inner-classes-actually-subclasses