A large chunk of the Classes and Objects tutorial deals with Nested ClassesInner Classes, Local Classes,Anonymous Classes, Lambda Expressions, and Method References. All these provide ways to:

  • logically group classes that are only used in one place
  • increase use of encapsulation as the outer class can have private members that the inner class can access
  • create more readable and maintainable code

The end of the tutorial has some suggestions about which approach to use. I’m starting with this before diving into the detail:

Choosing An Approach

  • Nested Class
    Use when you want to group classes and increase encapsulation. Use where you want a local class to be more widely available but you don’t need access to local variables or method parameters.

    • Non-Static / Inner Class
      Use if you need access to instance non-public fields/methods.
    • Static Nested Class
      Use if you don’t need instance access.
  • Local Class

Use if you need to create more than one instance, access its constructor, or introduce a new named type, e.g. to invoke additional methods later on.

  • Anonymous Class

Use if you only need to use a local class once, e.g. declaring and instantiating a class at the same time, and still need to declare fields and additional methods.

  • Lambda Expression

Use if encapsulating a single unit of behaviour to pass to other code.

Use if you need a simple instance of a functional interface and you don’t need, e.g. a constructor, a named type, fields, additional methods.

  • Method Reference

When a lambda expression does nothing but call an existing method, it’s often clearer to refer to the existing method by name.

Nested Class

2 types:

  1. Static called Static Nested Classes
  2. Non-Static called Inner Classes
class OuterClass {
    ...
    static class StaticNestedClass {
        ...
    }
    class InnerClass {
        ...
    }
}
  • Member of enclosing class.
  • Unlike the outer class, an inner class can be declared private, public, protected or package-private.

Static Nested Class

  • Only a nested class can be static. A top-level class cannot.
  • A static nested class can be declared within another static nested class but not within an inner classThis is so the parent class does not have to be instantiated to access the nested class.
  • Static nested classes are accessed using the enclosing class name:
    OuterClass.StaticNestedClass
  • An object can be created for the static nested class:
    OuterClass.StaticNestedClass nestedObject =
         new OuterClass.StaticNestedClass();

    Why would you want to create an object? e.g.

    class OuterClass{
    static int data=30;
    
    static class StaticNestedClass {
      void msg() {
        System.out.println("data is "+data);
      }
    }
    
    public static void main(String args[]){
    
      // error: non-static method msg() cannot be referenced from a static
      // context
      OuterClass.StaticNestedClass.msg(); 
    
      // Instead you need an object
      new OuterClass.StaticNestedClass().msg();
     }
    }

Inner Class

  • Non-Static Nested Classes (Inner Classes) have access to members of the enclosing class even if they are private.
  • An instance of an inner class can only exist within an instance of an outer class.
  • As an inner class is associated with an instance, it cannot define static members.
  • To instantiate an inner class you must use an outer object.
    OuterClass.InnerClass innerObject = outerObject.new InnerClass();
  • Do not serialise inner classes as synthetic constructs created at compile time differ between compilers which means .class files can differ which can cause problems serialising and deserializing with different JREs.
  • ShadowingIf 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 (lower level) shadows the declaration of the enclosing scope (higher level).
    public class OuterClass {
    
        public int x = 0; // declaration in enclosing scope. Is shadowed.
    
        class InnerClass {
    
            public int x = 1; // Shadows declaration in top level class
    
            void innerClassMethod (int x) { // shadows declaration in inner class
                // Parameter x : 23
                System.out.println("x = " + x);
                // this refers to Inner Class x : 1
                System.out.println("this.x = " + this.x);
                // this refers to Outer Class x : 0
                System.out.println("OuterClass.this.x = " + OuterClass.this.x);
            }
        }
    
        public static void main(String... args) {
            OuterClass oc = new OuterClass();
            OuterClass.InnerClass ic = oc.new InnerClass();
            ic.innerClassMethod(23);
        }
    }

Local Class

  • Inner class defined in a block (0 or more statements between braces), typically the body of a method, but could be in a for loop or an if clause.
    class CheckPersonEligibleForSelectiveService implements CheckPerson {
      public boolean test(Person p) {
        return p.getGender() == Person.Sex.MALE
           && p.getAge() >= 18
           && p.getAge() <= 25;
        }
    }
  • Has access to members of its enclosing class.
  • Can access a final local variable which is then called a captured variable.
  • Java SE 8: Local class can access an effectively final local variable.
  • Java SE 8: Local class in a method can access the method’s parameters ( as long as they remain effectively final )
  • May have static members that are constant variables

Anonymous Class

  • Local class declared WITHOUT A NAME
  • Statements are not allowed in the body
    InterfaceOrClass anonymousClassObject = new InterfaceOrClass() {
                String field = "field declaration is allowed";
                public void aMethod() {
                    System.out.println("output " + field);
                }
            };
  • Has access to members of its enclosing class.
  • A note on scope with a declaration within a method

The {} of the anonymous class statement in the example doesn’t change the scope of the object. You can still reference the object in the class body to call another method in the same way you could within the () of the object method.

object.method(new Interface () {
  object.anotherMethod();
});
  • An expression rather than class declaration so must be part of a statement that initializes an object.
  • Instance creation expression uses an interface to implement or class to extend.
  • If using an interface, there is no constructor, so parentheses are empty
  • Uses:
    • Make code more concise.
    • Declare and instantiate a class at the same time.
    • Good idea if a local class is only going to be used once.
    • Ideal for implementing an interface with 2+ methods.

 

The exercise notes for this tutorial are here

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s