How Can "This" of the Outer Class Be Accessed from an Inner Class

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.

How can I access OuterClass field from InnerClass?

Simply by doing OuterClass.this and the name of the field from the OuterClass that you want to access, for instance OuterClass.this.OuterName. In your code would look like the following:

public class OuterClass {
public String name; // field which has same name
public OuterClass(String name) {
this.name = name;
}
public class InstanceInnerClass {
public String name; // field which has same name
public InstanceInnerClass(String name) {
this.name = name;
}
public void printAllName() {
// What should be written in this code
// to print both name fields from OuterClass and InnerClass
System.out.printf("OuterName: %s, InnerName: %s\n", name, OuterClass.this.name);
}
}
}

When you have two fields with the same name one in the inner class and the other on the outer class (i.e., shadowing), and you try to access from the inner class that field, the compiler assumes that you want to access the field from the inner class, and ignores the other from the outer class. Otherwise, it would be impossible to choose, which variable to use.

Shadowing

If a declaration of a type (such as a member variable or a parameter
name) in a particular scope (such as an inner class or a method
definition) has the same name as another declaration in the enclosing
scope
, then the declaration shadows the declaration of the enclosing
scope. You cannot refer to a shadowed declaration by its name alone.

How can this of the outer class be accessed from an inner class?

You can access the instance of the outer class like this:

Outer.this

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.

Accessing outer-class fields through inner-class instance from outer-class

Why can't I access the outer classes field through an instance of
inner class in outer class in line 8?

Because the field is a field of the class OuterClass and not of the class InnerClass. So to access it, you need an instance of the class OuterClass, not of the class InnerClass.

Sure, inside InnerClass definition, you can implicitly access all the fields of OuterClass. But that's only a matter of access from inside this context. You're not specifying what is the object of which you're trying to access the field, so the language automatically selects that for you. It's usually this.field, but in the case of a field from the containing class, it's actually OuterClass.this.field.

Once you're trying to indicate what is the object of which you're trying to access a field, rather than let the language implicitly select that object for you, well this object must actually be of the class that contains the field.

How exactly do inner classes access elements in an outer class?

Inner class instances access the fields and methods of their outer class instance like any object accesses fields and methods of another object. The only difference is that, to be able to access private members, the compiler generates synthetic bridge methods (that are not private), called by the inner class, to access the private members.

See for example thus class:

public class Outer {
private int privateField;
public int publicField;

private void privateFoo() {}
public void publicFoo() {}

private class Inner {
void bar() {
privateFoo();
publicFoo();
System.out.println("privateField = " + privateField);
System.out.println("publicField = " + publicField);
}
}
}

If you compile it and call javap -c Outer Outer.Inner, you'll get the following output:

Compiled from "Outer.java"
public class com.foo.Outer {
public int publicField;

public com.foo.Outer();
Code:
0: aload_0
1: invokespecial #3 // Method java/lang/Object."<init>":()V
4: return

public void publicFoo();
Code:
0: return

static void access$000(com.foo.Outer);
Code:
0: aload_0
1: invokespecial #2 // Method privateFoo:()V
4: return

static int access$100(com.foo.Outer);
Code:
0: aload_0
1: getfield #1 // Field privateField:I
4: ireturn
}
Compiled from "Outer.java"
class com.foo.Outer$Inner {
final com.foo.Outer this$0;

void bar();
Code:
0: aload_0
1: getfield #1 // Field this$0:Lcom/foo/Outer;
4: invokestatic #3 // Method com/foo/Outer.access$000:(Lcom/foo/Outer;)V
7: aload_0
8: getfield #1 // Field this$0:Lcom/foo/Outer;
11: invokevirtual #4 // Method com/foo/Outer.publicFoo:()V
14: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
17: new #6 // class java/lang/StringBuilder
20: dup
21: invokespecial #7 // Method java/lang/StringBuilder."<init>":()V
24: ldc #8 // String privateField =
26: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
29: aload_0
30: getfield #1 // Field this$0:Lcom/foo/Outer;
33: invokestatic #10 // Method com/foo/Outer.access$100:(Lcom/foo/Outer;)I
36: invokevirtual #11 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
39: invokevirtual #12 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
42: invokevirtual #13 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
45: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
48: new #6 // class java/lang/StringBuilder
51: dup
52: invokespecial #7 // Method java/lang/StringBuilder."<init>":()V
55: ldc #14 // String publicField =
57: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
60: aload_0
61: getfield #1 // Field this$0:Lcom/foo/Outer;
64: getfield #15 // Field com/foo/Outer.publicField:I
67: invokevirtual #11 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
70: invokevirtual #12 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
73: invokevirtual #13 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
76: return
}

As you see, the Outer class has two additional static methods: access$000() and access$100(), which respectively call the private method and return the value of the private field. And the inner class goes through these methods to call the private method and access the private field.

The public method and fields are accessed in the usual way, though, since nothing prevents an object to access a public member of another object.

I'll let you do the same experiment on nested classes and static members to see how it works precisely.

Accessing outer class from within inner class using outerClass.this

  1. If your Engine class has a move method, then move() would be different from Car.this.move().

  2. this means the current instance. When you want to refer to the outer class, you are allowed to qualify the this keyword with the outer class to refer to the outer class's instance. The important thing to remember is that an instance of Engine (since it is not static) is always accompanied by an instance of Car and so you can refer to it.

You are not allowed to say OuterClass.smallEngine.move() because that would conflict with the syntax for accessing a static public field of OuterClass.

If OuterClass had a field like this:

 public static String smallEngine;

...then the above syntax would be ambigious. Since this is a keyword, you cannot have a field named this and therefore the syntax OuterClass.this will never be ambigious.

How to access outer class from an inner class?

The methods of a nested class cannot directly access the instance attributes of the outer class.

Note that it is not necessarily the case that an instance of the outer class exists even when you have created an instance of the inner class.

In fact, it is often recommended against using nested classes, since the nesting does not imply any particular relationship between the inner and outer classes.

Accessing outer class members from within an inner class extending the outer class itself

The method getValue() and the field value are both private. As such, they are not accessible to any other classes, including sub-classes, ie. they are not inherited.

In InnerClass#showValue()

public void showValue() {
System.out.println(getValue());
System.out.println(value);
}

because of the fact that those are private, getValue() and value are referring to the outer class' members, which are accessible because you are in the same class, ie. inner classes can access outer class private members. The above calls are equivalent to

public void showValue() {
System.out.println(TestInnerClass.this.getValue());
System.out.println(TestInnerClass.this.value);
}

And since you've set value as

new TestInnerClass("Initial value")

you see "Initial value" being printed twice. There is no way to access those private members in the sub-class.


The point is: don't make sub classes inner classes.



Related Topics



Leave a reply



Submit