JMU
Nested Classes
An Introduction with Examples in Java


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Motivation
Motivation
Nested Classes in UML

Containment

images/UML-nested-classes.gif
Two Different Approaches
Static Nested Classes
Static Nested Classes (cont.)
Static Nested Classes (cont.)

The Improved Implementation

javaexamples/nested/Course.java
import java.util.*;

/**
 * A simple encapsulation of a course.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 2.0 (Static Nested Classes)
 */
public class Course
{

    private int     credits;    
    private String  department, number;
    
    /**
     * Explicit Value Constructor.
     *
     * @param depatment   The department identifier (e.g., "CS")
     * @param number      The course nbumber (e.g., "159")
     * @param credits     The number of credits
     */
    public Course(String department, String number, int credits)
    {
        this.department = department;
        this.number     = number;
        this.credits    = credits;
    }
    
    /**
     * Returns the number of credits asscoiated with this Course.
     *
     * @return   The number of credits
     */
    public int getCredits()
    {
        return credits;
    }

    /**
     * Returns the ID of this Course.
     *
     * @return   The ID
     */
    public String getID()
    {
        return department + number;
    }

    /**
     * Return a String representation of this Course.
     *
     * @return   The String representation
     */
    public String toString()
    {
        return getID() + " (" + getCredits() + "cr)";
    }

    /**
     * A Comparator for Course objects that uses the number of credits.
     */
    public static class CreditComparator implements Comparator<Course>
    {
        /**
         * Compares two Course objects (using their credit hours)
         * (required by Comparator).
         *
         * @param a   Object a
         * @param b   Object b
         * @return   -1, 0, 1 (as per Comparator)
         */
        public int compare(Course a, Course b)
        {
            int     an, bn;
        
            an = a.getCredits();
            bn = b.getCredits();
        
            if      (an < bn) return -1;
            else if (an > bn) return  1;
            else              return  0;
        }
    }

    /**
     * A Comparator for Course objects that uses the ID.
     */
    public static class IDComparator implements Comparator<Course>
    {
        /**
         * Compares two Course objects (using their IDs)
         * (required by Comparator).
         *
         * @param a   Object a
         * @param b   Object b
         * @return   -1, 0, 1 (as per Comparator)
         */
        public int compare(Course a, Course b)
        {
            return a.getID().compareTo(b.getID());
        }
    }

}
        
Static Nested Classes (cont.)

Using the Static Nested Classes

javaexamples/nested/CourseDriver.java
import java.util.*;

/**
 * An application that can be used to demonstrate the power
 * of the Comparator interface.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 2.0 (Static Nested Classes)
 */
public class CourseDriver
{
    /**
     * The entry point of the application.
     *
     * @param args  The command-line arguments
     */
    public static void main(String[] args)
    {
        Comparator<Course>  comparator;        
        Course[]            prog;
        
        prog = new Course[3];
        prog[0] = new Course("CS", "240", 3);
        prog[1] = new Course("CS", "159", 3);
        prog[2] = new Course("CS", "139", 4);

        // Note that because IDComparator is a static nested class,
        // its constructor must be referred to using the name of the
        // outer class.
        comparator = new Course.IDComparator();        
        Arrays.sort(prog, comparator);
        
        System.out.println("\nSorted by ID:");        
        print(prog);
        
        comparator = new Course.CreditComparator();        
        Arrays.sort(prog, comparator);
        
        System.out.println("\nSorted by Credits:");        
        print(prog);
        
    }

    /**
     * Print an array of Course objects.
     *
     * @param courses   The array.
     */
    private static void print(Course[] courses)
    {
        for (int i=0; i<courses.length; i++) 
        {
            System.out.println(courses[i]);
        }
    }
}
        
Inner Classes
Inner Classes (cont.)
Inner Classes (cont.)
Inner Classes (cont.)

An Implementation without an Inner Class

javaexamples/iterator/ClosedInterval.java
import java.util.*;

/**
 * An encapsulation of a closed interval on the real line.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class ClosedInterval
{
    private double left, right;
    
    /**
     * Explicit value constructor.
     *
     * @param left  The lower bound of the interval
     * @param right The upper bound of the interval
     */
    public ClosedInterval(double left, double right)
    {
        this.left  = left;
        this.right = right;
    }
    
    /**
     * Get an increasing integer Iterator (i.e., from left to right)
     * for this interval.
     *
     * @return  The Iterator
     */
    public Iterator<Integer> getIncreasingIterator()
    {
        return new IncreasingIterator(this);
    }
    
    /**
     * Get the lower bound for this interval.
     *
     * @return  The lower bound
     */
    public double getLeft()
    {
        return left;
    }

    /**
     * Get the upper bound for this interval.
     *
     * @return  The upper bound
     */
    public double getRight()
    {
        return right;
    }
    
    
}
        
Inner Classes (cont.)

An Implementation without an Inner Class (cont.)

javaexamples/iterator/IncreasingIterator.java
import java.util.*;

/**
 * An Iterator that returns the Integer objects in a ClosedInterval
 * from left to right.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class IncreasingIterator implements Iterator<Integer>
{
    private ClosedInterval interval;    
    private int            next;
        
    /**
     * Constructor. 
     *
     * @param interval  The ClosedInterval to iterate over
     */
    public IncreasingIterator(ClosedInterval interval)
    {
        this.interval = interval;        
        next = (int)Math.ceil(interval.getLeft());
    }
        
    /**
     * Returns true if this Iterator has a next element,
     * and false otherwise.
     *
     * @return true or false as appropriate
     */
    public boolean hasNext()
    {
        return next <= interval.getRight();
    }

    /**
     * Return the next Integer in the interval.
     *
     * @return The next Integer.
     * @throws NoSuchElementException if there is no next Integer
     */
    public Integer next() throws NoSuchElementException
    {
        if (!hasNext()) throw new NoSuchElementException();
            
        int result;
            
        result = next;
        ++next;
            
        return Integer.valueOf(result);
    }
}
        
Inner Classes (cont.)

An Implementation with an Inner Class

javaexamples/nested/ClosedInterval.java
import java.util.*;

/**
 * An encapsulation of a closed interval on the real line.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 2.0 (Inner Class)
 */
public class ClosedInterval
{
    private double left, right;
    
    /**
     * Explicit value constructor.
     *
     * @param left  The lower bound of the interval
     * @param right The upper bound of the interval
     */
    public ClosedInterval(double left, double right)
    {
        this.left  = left;
        this.right = right;
    }
    
    /**
     * Get an increasing integer Iterator (i.e., from left to right)
     * for this interval.
     *
     * @return  The Iterator
     */
    public Iterator<Integer> getIncreasingIterator()
    {
        return new IncreasingIterator();
    }
    
    /**
     * Get the lower bound for this interval.
     *
     * @return  The lower bound
     */
    public double getLeft()
    {
        return left;
    }

    /**
     * Get the upper bound for this interval.
     *
     * @return  The upper bound
     */
    public double getRight()
    {
        return right;
    }
    
    /**
     * An Iterator that returns the Integer objects in this
     * interval from left to right.
     */
    private class IncreasingIterator implements Iterator<Integer>
    {
        private int next;
        
        /**
         * Constructor. 
         */
        private IncreasingIterator()
        {
            next = (int)Math.ceil(left);
        }
        
        /**
         * Returns true if this Iterator has a next element,
         * and false otherwise.
         *
         * @return true or false as appropriate
         */
        public boolean hasNext()
        {
            return next <= right;
        }

        /**
         * Return the next Integer in the interval.
         *
         * @return The next Integer.
         * @throws NoSuchElementException if there is no next Integer
         */
        public Integer next() throws NoSuchElementException
        {
            if (!hasNext()) throw new NoSuchElementException();
            
            int result;
            
            result = next;
            ++next;
            
            return Integer.valueOf(result);
        }
    }
    
}
        
Inner Classes (cont.)

Using the Inner Class

javaexamples/nested/IntervalDriver.java
import java.util.*;


/**
 * An application that can be used to demonstrate the use of
 * an inner class (i.e., a non-static nested class).
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 2.0 (Inner Classes)
 */
public class IntervalDriver
{
    /**
     * The entry point of the application.
     *
     * @param args  The command-line arguments
     */
    public static void main(String[] args)
    {
        ClosedInterval     interval;
        Iterator<Integer>  iterator;        
        
        interval = new ClosedInterval(3.7, 10.2);

        // Note because the IncreasingIterator class is an inner class
        // (i.e., non-static nested class), an instance of the
        // ClosedInterval class is needed to construct an instance of
        // the IncreasingIterator class.
        iterator = interval.getIncreasingIterator();

        while (iterator.hasNext())
        {
            System.out.printf("%d\n", iterator.next());
        }
    }
}
        
Beyond the Scope of this Lecture