This question already has answers here:
Why is an anonymous inner class containing nothing generated from this code?
(5 answers)
Closed 9 years ago.
I have an Outer class which has a private Inner class.
In my Outer class method, I instantiate the Inner class as follows:
Outer outer = new Outer();
Inner inner = outer.new Inner();
The compiler converts this code to:
Outer outer = new Outer();
Inner inner = new Inner(outer, null);
Using reflection shows that the Inner class has the following synthesized constructors:
private Outer$Inner(Outer)
Outer$Inner(Outer,Outer$Inner)
Since the Inner class is private, the compiler adds that private constructor to it so nobody can instantiate that class. But obviously the Outer class should be able to instantiate it, so the compiler adds that other package private constructor which in turn calls the private constructor. Also, since the package-private constructor has that $ in its name, normal Java code can't call it.
Question: why synthesize one private and one package-private constructor? Why not synthesize only the package-private constructor and be done with it?
If you write the code like,
public class Outer {
private class Inner {}
}
You will note that there is only one constructor private Outer$Inner(Outer)
This constructor is required by Section 8.8.9 of the JLS, which says that if no constructor is defined a default constructor must be generated, and in this case the default constructor must be private,
In a class type, if the class is declared public, then the default
constructor is implicitly given the access modifier public (§6.6); if
the class is declared protected, then the default constructor is
implicitly given the access modifier protected (§6.6); if the class is
declared private, then the default constructor is implicitly given the
access modifier private (§6.6); otherwise, the default constructor has
the default access implied by no access modifier.
However, when you you instantiate an instance of Inner inside Outer with code like,
public class Outer {
private class Inner {}
public String foo() {
return new Inner().toString();
}
}
The compiler has to generate a constructor that Outer can legally call (you can't legally call the private default constructor because it is private). So a new synthetic constructor must be generated by the compiler. The new constructor must be synthetic, according to section 13.1 of the JLS
Any constructs introduced by the compiler that do not have a
corresponding construct in the source code must be marked as
synthetic, except for default constructors and the class
initialization method.
This second constructor has no corresponding construct in the source code, so this new constructor must be synthetic. The first private constructor must still be generated, since the JLS requires a private default constructor.
This is not an answer, which I think has been well covered by sbridges. It is simply a working example that produces the behaviour you describe:
public class Outer {
private class Inner {
}
public static void main(String[] args) {
printConstructors();
//only one constructor is printed but two would appear if you
//uncommented the line below
//new Outer().new Inner();
}
private static void printConstructors() {
Constructor[] constructors = Outer.Inner.class.getDeclaredConstructors();
for (Constructor c : constructors) {
System.out.println(c.toGenericString());
}
}
}
The most likely answer is to respect what you declared in your source code. Doing this still allows to use the private constructor by reflection as you declared it.
This also avoids to check whether the private constructor is actually called within the Inner class.
Related
Say I have class A with a private constructor, and class B that extends it:
public class A {
private A() {}
}
public class B extends A {
public B(){
// error - there is no default constructor available in 'A'
}
}
I know it is possible to call private constructors via Java Reflection, but how can I do it in the B constructor? Thanks.
If class B extends A and A's constructor is private, subclassing is not possible unless both classes are defined in the same file as inner classes (see Preventing Instantiation of a Class). That's because the constructor of the subclass does an (either explicit or implicit) super() call. A super() call is basically just a call to the matching constructor and if that constructor is declared private, this call is not possible from some outer class (e.g. one defined in a different file).
I don't understand why this compiles. f() and g() are visible from the inner classes, despite being private. Are they treated special specially because they are inner classes?
If A and B are not static classes, it's still the same.
class NotPrivate {
private static class A {
private void f() {
new B().g();
}
}
private static class B {
private void g() {
new A().f();
}
}
}
(Edit: expanded on the answer to answer some of the comments)
The compiler takes the inner classes and turns them into top-level classes. Since private methods are only available to the inner class the compiler has to add new "synthetic" methods that have package level access so that the top-level classes have access to it.
Something like this (the $ ones are added by the compiler):
class A
{
private void f()
{
final B b;
b = new B();
// call changed by the compiler
b.$g();
}
// method generated by the compiler - visible by classes in the same package
void $f()
{
f();
}
}
class B
{
private void g()
{
final A a;
a = new A();
// call changed by the compiler
a.$f();
}
// method generated by the compiler - visible by classes in the same package
void $g()
{
g();
}
}
Non-static classes are the same, but they have the addition of a reference to the outer class so that the methods can be called on it.
The reason Java does it this way is that they did not want to require VM changes to support inner classes, so all of the changes had to be at the compiler level.
The compiler takes the inner class and turns it into a top level class (thus, at the VM level there is no such thing as an inner class). The compiler then also has to generate the new "forwarding" methods. They are made at the package level (not public) to ensure that only classes in the same package can access them. The compiler also updated the method calls to the private methods to the generated "forwarding" methods.
You can avoid having the compiler generate the method my declaring the methods as "package" (the absence of public, private, and protected). The downside to that is that any class in the package can call the methods.
Edit:
Yes, you can call the generated (synthetic) method, but DON'T DO THIS!:
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Main
{
public static void main(final String[] argv)
throws Exception
{
final Class<?> clazz;
clazz = Class.forName("NotPrivate$A");
for(final Method method : clazz.getDeclaredMethods())
{
if(method.isSynthetic())
{
final Constructor constructor;
final Object instance;
constructor = clazz.getDeclaredConstructor(new Class[0]);
constructor.setAccessible(true);
instance = constructor.newInstance();
method.setAccessible(true);
method.invoke(null, instance);
}
}
}
}
I think this quote sums it up nicely:
...inner classes can access all members of the declaring class, even private members. In fact, the inner class itself is said to be a member of the class; therefore, following the rules of object-oriented engineering, it should have access to all members of the class.
And following from that, since both inner classes are really just part of the containing class, they should be able to access each others private members as well.
Java compiles in special accessors with $ in them. So you can't write Java that access the private methods. Explained here:
http://www.retrologic.com/innerclasses.doc7.html
There is one more category of compiler-generated members. A private member m of a class C may be used by another class D, if one class encloses the other, or if they are enclosed by a common class. Since the virtual machine does not know about this sort of grouping, the compiler creates a local protocol of access methods in C to allow D to read, write, or call the member m. These methods have names of the form access$0, access$1, etc. They are never public. Access methods are unique in that they may be added to enclosing classes, not just inner classes.
As User 'A Dude' explained it in the comments of the accepted answer:
It compiles, because it is required to be working in that way by the language specifation, ie. the Java Lang Spec says so:
6.6.1 Determining Accessibility (at least since JLS6)
"Otherwise, if the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor."
I.e. the "access-scope" of a private member is: everywhere within the lexical boundaries of the top-level class body.
That means: all private members that are defined within the class-body of the outermost class can be accessed from everywhere else in this class-body.
For instance the private method of an inner class can be accessed from methods of the outer class or from any method of another inner class of the outer class.
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?
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.
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".
Subclass and inner class are two different 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.
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? :)
Consider the below example
Why we are restricted to declare static member variable in inner Class when there isn't any restriction on inheriting static variables in Inner classes?
public class Outer {
public class Inner {
public static String notAllowed;
/* Above line give following compilation error
The field notAllowed cannot be declared static in a non-static inner type, unless initialized with a constant expression
*/
}
}
But now if my inner class extends other class which contains static variable than this works fine.
Consider below code:
public class Outer {
public class Inner extends InnerBase {
/* Since it extends InnerBase so we can access Outer.Inner.allowed */
public Inner(){
Outer.Inner.allowed = null; // Valid statement
}
}
}
public class InnerBase {
public static String allowed;
}
So what is the reason for restricting static variable in inner class as it is achievable through inheritance?
Am I missing something very basic?
From oracle website:
As with instance methods and variables, an inner class is associated with an instance of its enclosing class and has direct access to that object's methods and fields.
Because an inner class is associated with an instance, it cannot define any static members itself.
I understand it this way:
If inner class have their own static field,and static field have to initialize before class instantiate;
But a innner class only exist with an instance of outterclass ,so it can not initialize its static member before instantiate,then in Contradiction.
Because in order to access the static field, you will need an instance of the Outer class, from which you will have to create an instance of the non-static Inner class.
static fields are not supposed to be bound to instances and therefore you receive a compilation error.
The JLS 8.1.3 specifies:
Inner classes may not declare static initializers or member
interfaces, or a compile-time error occurs.
Inner classes may not declare static members, unless they are constant
variables, or a compile-time error occurs.
It is very much possible that the purpose of declaring a static variable opposes the purpose of declaring ANY variable in an inner class. Static variables are meant to be used statically - in any other static methods and classes, while inner classes imply that those classes serve their outer classes ONLY.
I guess the Java creators just wanted it this way.
I was trying to test working of private interfaces and wrote the code below. I can understand that a situation might arise to declare private interfaces if we don't want any other class to implement them but what about variables? Interface variables are implicitly public static final and hence i was able to access them even if interface was declared private. This can be seen in code below.
public class PrivateInterfaceTest {
/**
* #param args
*/
public static void main(String[] args) {
TestingInterfaceClass test = new TestingInterfaceClass();
TestingInterfaceClass.inner innerTest = test.new inner();
System.out.println(innerTest.i);
}
}
class TestingInterfaceClass {
private interface InnerInterface {
int i = 0;
}
class inner implements InnerInterface {
}
}
Does it mean that we can never really have private interface in true sense? And does it really make sense to if have private interface if we can access variables outside private interface?
EDIT:
Just want to add that same situation will not arise if we have private inner class. A private variable in inner class will never get exposed.
Your member interface is private. The inherited static field is not private.
A private member interface cannot be used as a type outside the enclosing top-level class or enum. This can be useful to prevent external code from implementing an interface you may wish to change. From the JLS:
The access modifiers protected and private pertain only to member interfaces within a directly enclosing class or enum declaration (§8.5.1).
The interface field is public, and inherited by the class that implements the interface. From the JLS:
A class inherits from its direct superclass and direct superinterfaces all the non-private fields of the superclass and superinterfaces that are both accessible to code in the class and not hidden by a declaration in the class.
If you want to make the field accessible only within the classes that implement the member interface, you can put its declaration in the enclosing top-level scope.
class TestingInterfaceClass {
private static final int i = 0;
private interface InnerInterface {
// ...
}
class inner implements InnerInterface {
// ...
}
}
As I see, it is not the problem with private interface InnerInterface. It is the inner class which is at default scope inside TestingInterfaceClass exposing the content of InnerInterface. If you don't want the content of InnerInterface to be known to the world, you should also declare all the classes (specifically TestingInterfaceClass) as private.
Because every variable in an interface is public static final, it should be the responsibility of the class (implementing it) whether it should take care of the content inherited from private interface
Even though it's allowed, we don't need (and shouldn't use) an instance to access an static field.
Following is the way to access it -
System.out.println(TestingInterfaceClass.inner.i);
//note you cannot access the InnerInterface like this here because it's private
The inner has inherited the public static field i and i should be visible wherever the inner itself is visible.
Usually, interfaces are used to expose the behaviors of an object, while the implementations are hidden. But in your case, you are attempting the opposite.
The Interface variables are implicitly public static final, but you can't reach this variables because you can't reach previously the interface that contains these variable, which you have declared as private. First you need to be able to see the interface, and after that, go into content of the interface.