del_champ
del_champ

Reputation: 179

How are private members of a class accessed via member functions of the class on memory level?

class TestMemberOuter1{
 private int data=30;
 class Inner{
  void msg(){System.out.println("data is "+data);}
 }

 void display(){
  Inner in=new Inner();
  in.msg();
 }
 public static void main(String args[]){
  TestMemberOuter1 obj=new TestMemberOuter1();
  obj.display();
 }
}

Why innerclass is able to access private members of the outerclass ?

I want to know what implementation [ at the lower level (Maybe at memory level or java implementation specific or any other not sure)] enables to achieve this kind of behaviour in java .

Upvotes: 1

Views: 125

Answers (2)

Holger
Holger

Reputation: 298143

Currently, inner classes are compiled into distinct class files, but the compiler will insert synthetic helper methods when there is an access to a private member across nested classes. The synthetic method itself will have package-private access and perform the access to the private member within its own class.

This can be demonstrated with private methods as their execution can be traced and will show the execution of these helper methods:

public class OuterClass {
    static class InnerClass {
        private static void test() {
            OuterClass.privateMethod();
        }
    }
    private static void privateMethod() {
        Thread.dumpStack();
    }
    public static void main(String[] args) {
        InnerClass.test();
    }
}

Running this program will print:

java.lang.Exception: Stack trace
    at java.lang.Thread.dumpStack(Thread.java:1329)
    at OuterClass.privateMethod(OuterClass.java:9)
    at OuterClass.access$000(OuterClass.java:2)
    at OuterClass$InnerClass.test(OuterClass.java:5)
    at OuterClass$InnerClass.access$100(OuterClass.java:3)
    at OuterClass.main(OuterClass.java:12)

These nested classes are compiled into two distinct class files OuterClass.class and OuterClass$InnerClass.class. You can see that the compiler has inserted the synthetic method access$100 into OuterClass$InnerClass which allows the main method of OuterClass to invoke the private method test of the inner class. This inner class method in turn invoked a synthetic method access$000 in the outer class which allows the invocation of privateMethod() in OuterClass.


Note that this kind of access is different to the access to private members performed with Java 8’s lambda expressions and method references. For the member access performed in that context, no helper methods are generated by the compiler and the way the JVM makes the access possible is intentionally unspecified, but we can say that for Oracle’s current JRE implementation, there will be a runtime-generated class which is indeed capable of bypassing the access restriction of private members, e.g.

import java.util.function.Consumer;

public class OuterClass {
    static class InnerClass {
        static final Consumer<Runnable> TEST_METHOD=InnerClass::test;
        private static void test(Runnable outerMethod) {
            outerMethod.run();
        }
    }
    private static void privateMethod() {
        Thread.dumpStack();
    }
    public static void main(String[] args) {
        System.out.println(System.getProperty("java.version"));
        InnerClass.TEST_METHOD.accept(OuterClass::privateMethod);
    }
}

As of 1.8.0_65, it prints:

java.lang.Exception: Stack trace
    at java.lang.Thread.dumpStack(Thread.java:1329)
    at OuterClass.privateMethod(OuterClass.java:12)
    at OuterClass$InnerClass.test(OuterClass.java:8)
    at OuterClass.main(OuterClass.java:16)

Not showing such helper methods, but also filtering out the runtime-generated classes. Changing privateMethod() to

private static void privateMethod() {
    for(StackTraceElement e:Thread.getAllStackTraces().get(Thread.currentThread()))
        System.out.println("\tat "+e);
}

reveals

    at java.lang.Thread.dumpThreads(Native Method)
    at java.lang.Thread.getAllStackTraces(Thread.java:1603)
    at OuterClass.privateMethod(OuterClass.java:12)
    at OuterClass$$Lambda$2/135721597.run(Unknown Source)
    at OuterClass$InnerClass.test(OuterClass.java:8)
    at OuterClass$InnerClass$$Lambda$1/471910020.accept(Unknown Source)
    at OuterClass.main(OuterClass.java:16)

with the generated classes having fancy names like OuterClass$InnerClass$$Lambda$1/471910020 and OuterClass$$Lambda$2/135721597 which are accessing the private members. Note that the generation of these classes has been triggered by the classes which have the right to access these private members, which has been checked before allowing to create such function objects.

Upvotes: 1

Sandeep Bhandari
Sandeep Bhandari

Reputation: 20369

I dont think neither you need any memory level modifictaion or logic implementation to achieve this nor I think java will have any huge code logic at memory level to implement the same.

Memory has got nothing to do with it. Private, public and protected are just a access filters, No matter whether it is a private, public or protected all these variables will reside in a same memory which is allocated for an object.

There is no differrent memory allocation for private, public or protected variables. They are all ultimately the properties of same object.

Then how come compiler handles this ???

Its bit simpler than that.

These access filters clearly informs in what context they should be allowed to access.

Private : Only whitin the class :) Whenever compiler sees the variable which is provate being accessed any where out side the class it will flag the error Thats all.

Protected : All class within the same package :) Whenever compiler sees the variable which is Protected being accessed any where out package it will flag the error Thats all.

Public : Access to all :) No flags.

Remember accessing variables outside context results in compiler error not runtime error ?? For the same reason.

You dont need a huge logic behind it, Just keep the list of private, protected and public variables and check their usage is appropriate or not thats all.

EDIT As per your updated question "Why innerclass is able to access private members of the outerclass ?"

Drawing the conclusion from the same analogy I explained above, private variables are allowed to be accessed anywhere within the class.

Now where is your innerclass declared? As a part of your outer class itself isn't it. So when you access the private variable of outer class inside the inner class compiler has no issue with it, because your inner class itself resides inside the outer class.

I hope I made a little sense with my answer :) Happy coding.

Upvotes: 3

Related Questions