Accessing Members in Enclosing Context – Nested Type Declarations

Accessing Members in Enclosing Context

An implicit reference to the enclosing object is always available in every method and constructor of a non-static member class. A method or constructor can explicitly specify this reference using a special form of the this construct and access its enclosing object, as explained in the next example.

From within a non-static member class, it is possible to refer to all members in the enclosing class directly, unless they are hidden. An example is shown at (9) in Example 9.5, where the instance field message in an object of the enclosing class is accessed by its simple name in the non-static member class. It is also possible to explicitly refer to members in the enclosing class, but this requires special usage of the this reference. One might be tempted to write the statement at (9) as follows:

Click here to view code image

return this.message + ” in ” + this.nodeInfo +
                        ” (” + this.maxNumOfNodes + “)”;          // (9a) Not ok.

The reference this.nodeInfo is correct because the field nodeInfo certainly belongs to the current object (denoted by this) of the Node class, but this.message cannot possibly work, as the current object (indicated by this) of the Node class has no field named message. The correct syntax is the following:

Click here to view code image

return MyLinkedList.this.message + ” in ” + this.nodeInfo +
                                     ” (” + this.maxNumOfNodes + “)”; // (9b)

The expression (called the qualified this)

enclosing_class_name
.this

evaluates to a reference that denotes the enclosing object (of the specified class) that is associated with the current instance of a non-static member class.

Accessing Hidden Members

Fields and methods in the enclosing context can be hidden by fields and methods with the same names in the non-static member class. The qualified this can be used to access members in the enclosing context, somewhat analogous to using the keyword super in subclasses to access hidden superclass members.

Example 9.6 Qualified this and Qualified Class Instance Creation Expression

Click here to view code image

// File: OuterInstances.java
class TLClass {                                            // (1)  TLC
  private String id = “TLClass “;                          // (2)
  public TLClass(String objId) { id = id + objId; }        // (3)
  public void printId() {                                  // (4)
    System.out.println(id);
  }
  class InnerB {                                           // (5)  NSMC
    private String id = “InnerB “;                         // (6)
    public InnerB(String objId) { id = id + objId; }       // (7)
    public void printId() {                                // (8)
      System.out.print(TLClass.this.id + ” : “);           // (9)  Refers to (2)
      System.out.println(id);                              // (10) Refers to (6)
    }
    class InnerC {                                         // (11) NSMC
      private String id = “InnerC “;                       // (12)
      public InnerC(String objId) { id = id + objId; }     // (13)
      public void printId() {                              // (14)
        System.out.print(TLClass.this.id + ” : “);         // (15) Refers to (2)
        System.out.print(InnerB.this.id + ” : “);          // (16) Refers to (6)
        System.out.println(id);                            // (17) Refers to (12)
      }
      public void printIndividualIds() {                   // (18)
        TLClass.this.printId();                            // (19) Calls (4)
        InnerB.this.printId();                             // (20) Calls (8)
        printId();                                         // (21) Calls (14)
      }
    } // InnerC
  } // InnerB
} // TLClass
//_____________________________________________________________________________
public class OuterInstances {                                // (22)
  public static void main(String[] args) {                   // (23)
    TLClass a = new TLClass(“a”);                            // (24)
    TLClass.InnerB b = a.new InnerB(“b”);                    // (25) b  –> a
    TLClass.InnerB.InnerC c1 = b.new InnerC(“c1”);           // (26) c1 –> b
    TLClass.InnerB.InnerC c2 = b.new InnerC(“c2”);           // (27) c2 –> b
    b.printId();                                             // (28)
    c1.printId();                                            // (29)
    c2.printId();                                            // (30)
    System.out.println(“————“);
TLClass.InnerB bb = new TLClass(“aa”).new InnerB(“bb”);  // (31)
    TLClass.InnerB.InnerC cc = bb.new InnerC(“cc”);          // (32)
    bb.printId();                                            // (33)
    cc.printId();                                            // (34)
    System.out.println(“————“);
    TLClass.InnerB.InnerC ccc =
      new TLClass(“aaa”).new InnerB(“bbb”).new InnerC(“ccc”);// (35)
    ccc.printId();                                           // (36)
    System.out.println(“————“);
    ccc.printIndividualIds();                                // (37)
  }
}

Output from the program:

Click here to view code image

TLClass a : InnerB b
TLClass a : InnerB b : InnerC c1
TLClass a : InnerB b : InnerC c2
————
TLClass aa : InnerB bb
TLClass aa : InnerB bb : InnerC cc
————
TLClass aaa : InnerB bbb : InnerC ccc
————
TLClass aaa
TLClass aaa : InnerB bbb
TLClass aaa : InnerB bbb : InnerC ccc

Example 9.6 illustrates the qualified this employed to access members in the enclosing context, and also demonstrates the qualified class instance creation expression employed to create instances of non-static member classes. The example shows the non-static member class InnerC at (11), which is nested in the non-static member class InnerB at (5), which in turn is nested in the top-level class TLClass at (1). All three classes have a private non-static String field named id and a non-static method named printId. The member name in the nested class hides the name in the enclosing context. These members are not overridden in the nested classes because no inheritance is involved. In order to refer to the hidden members, the nested class can use the qualified this, as shown at (9), (15), (16), (19), and (20).

Within the nested class InnerC, the three forms used in the following statements to access its field id are equivalent:

Click here to view code image

System.out.println(id);                      // (17)
System.out.println(this.id);                 // (17a)
System.out.println(InnerC.this.id);          // (17b)

The main() method at (23) uses the special syntax of the new operator to create objects of non-static member classes and associate them with enclosing objects. An instance of class InnerC (denoted by c1) is created at (26) in the context of an instance of class InnerB (denoted by b), which was created at (25) in the context of an instance of class TLClass (denoted by a), which in turn was created at (24).

Click here to view code image

TLClass a = new TLClass(“a”);                            // (24)
TLClass.InnerB b = a.new InnerB(“b”);                    // (25) b  –> a
TLClass.InnerB.InnerC c1 = b.new InnerC(“c1”);           // (26) c1 –> b

The reference c1 is used at (29) to invoke the method printId() declared at (14) in the nested class InnerC. This method prints the field id from all the objects associated with an instance of the nested class InnerC.

Click here to view code image

TLClass a : InnerB b : InnerC c1

When the intervening references to an instance of a non-static member class are of no interest—that is, if the reference values need not be stored in variables—the new operator can be chained as shown at (31) and (35).

Click here to view code image

TLClass.InnerB bb = new TLClass(“aa”).new InnerB(“bb”);  // (31)

TLClass.InnerB.InnerC ccc =
  new TLClass(“aaa”).new InnerB(“bbb”).new InnerC(“ccc”);// (35)

Note that the (outer) objects associated with the instances denoted by the references c1, cc, and ccc (at (26), (32), and 35), respectively) are distinct, as evident from the program output. However, the instances denoted by references c1 and c2 (at (26) and (27), respectively) have the same outer objects associated with them.

Leave a Reply

Your email address will not be published. Required fields are marked *