Why Can Outer Java Classes Access Inner Class Private Members

Can an outer class access the members of inner class?

If the inner class defined as private
and protected, can outer class access
the members of inner class?

Yes. These qualifiers will only affect the visibility of the inner class in classes that derive from the outer class.

Can inner class access members of
outer class?

Yes, including the ones declared private, just as any instance method can.

Why can outer Java classes access inner class private members?

The inner class is just a way to cleanly separate some functionality that really belongs to the original outer class. They are intended to be used when you have 2 requirements:

  1. Some piece of functionality in your outer class would be most clear if it was implemented in a separate class.
  2. Even though it's in a separate class, the functionality is very closely tied to way that the outer class works.

Given these requirements, inner classes have full access to their outer class. Since they're basically a member of the outer class, it makes sense that they have access to methods and attributes of the outer class -- including privates.

Inner classes can access even the private members of the outer class.. doesn't it violates the privacy?

From a JVM perspective, yes, an inner class accessing a private member of the outer class violates privacy.

But, from a Java perspective, no, it does not violate privacy.

JVM perspective

The Java Virtual Machine Specification, section 5.4.4. Access Control says:

A field or method R is accessible to a class or interface D if and only if any of the following is true:

  • [...]

  • R is private and is declared in D.

So, the JVM will only allow private members to be accessed from code in the same class, i.e. a nested class cannot access private members of the outer class.

Java perspective

The Java Language Specification, section 6.6.1. Determining Accessibility says:

A member (class, interface, field, or method) of a reference type, or a constructor of a class type, is accessible only if the type is accessible and the member or constructor is declared to permit access:

  • [...]

  • Otherwise, the member or constructor is declared private, and 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.

So, a private member in a top-level class and/or nested class is accessible from code anywhere within that top-level class. Since nested classes by definition occur within the body of the enclosing top-level class, code in nested classes can access private members of the outer class.

Synthetic access

To solve the discrepancy, the Java compiler creates hidden (synthetic) methods for allowing "private" access between closely related classes, i.e. between a top-level class and all its nested classes.

This is an internal trick of the compiler and is not really documented in the specifications. JVMS, section 4.7.8. The Synthetic Attribute says:

[...] A class member that does not appear in the source code must be marked using a Synthetic attribute, or else it must have its ACC_SYNTHETIC flag set. [...]

The Synthetic attribute was introduced in JDK 1.1 to support nested classes and interfaces.

For more information, do a web search for java synthetic accessor.

See also: Synthetic accessor method warning

How do inner class access enclosing class' private members in higher versions of Java?

The only thing that stops a class from accessing another class’s private members, is the JVM (or precisely its verifier) rejecting the access. So all it needs to make it possible, is the collaboration of the JVM to allow it.

While Java 1.1 introduced inner classes in a way that did not require changes to the JVM, the JVM has gone through so many changes in the meanwhile, that it is rather surprising that it took until Java 11 to change that.

Java 11 introduced the NestHost and NestMembers bytecode attributes to allow class files to denote that they belong to a so called “nest”. All classes belonging to the same nest are allowed to access each others private members. As said, the only thing that needed to be changed, is the JVM’s verifier to allow such access. And, of course, the compiler to utilize this feature. See also JEP 181.

So you could say that the JVM still doesn’t know anything about inner classes, because which classes belong to a nest, is decided by whichever tool generated the class files (e.g. the Java source code compiler). So it is possible to produce class files with other tools using nests without following the inner class semantic.

For completion, it should be mentioned that class files do also contain the information about inner class relationships, using the InnerClasses attribute. But this is only used by compilers and Reflection, whereas the JVM doesn’t use this information when deciding whether an access is legal or not.

Why can outer Java classes access inner class private members?

The inner class is just a way to cleanly separate some functionality that really belongs to the original outer class. They are intended to be used when you have 2 requirements:

  1. Some piece of functionality in your outer class would be most clear if it was implemented in a separate class.
  2. Even though it's in a separate class, the functionality is very closely tied to way that the outer class works.

Given these requirements, inner classes have full access to their outer class. Since they're basically a member of the outer class, it makes sense that they have access to methods and attributes of the outer class -- including privates.

Access inner class private vars from outer class

If the field is static, you already can access it from the outer class even if it's private. You don't need an instance of either the inner or the outer class:

public class Clazz {
class Inner {
private static final int N = 10;
}
public static void main(String[] args) {
System.out.println(Inner.N);
}
}

If the inner class field is not static, it does not exist without an instance of the inner class. You can't access something that doesn't exist.

Private member of a Static Nested Class in Java

The inner class is just a way to cleanly separate some functionality that really belongs to the original outer class.

The inner class is (for purposes of access control) considered to be part of the containing class. This means full access to all privates.

The way this is implemented is using synthetic package-protected methods: The inner class will be compiled to a separate class in the same package. The JVM does not support this level of isolation directly, so that at the bytecode-level will have package-protected methods that the outer class uses to get to the private methods/fields.

If you like to hide the private members of your inner class, you may define an Interface with the public members and create an anonymous inner class that implements this interface.

In Java nested classes, can the enclosing class access private members of inner classes?

Yes, that's fine. From the JLS, section 6.6.1:

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.

You can even refer to a private member of nested type X within another nested type Y so long as they share a top-level class.

At the bytecode level, I believe this is all implemented by adding synthetic package-access methods.



Related Topics



Leave a reply



Submit