Intro To Java Classes Revisited

This entry is part 3 of 13 in the series Intro to Java

This lesson will look more at class concepts in Java: Extending, overriding, composition, and inner classes. It was created as a lesson for a class room setting. I have converted it to a post here.

Is a Class just a Class?

I recently heard that the classic contractor response to a question is “Well, it depends.” That might just apply here. There are several different types of classes. There are regular classes, like we have been using, there are inner classes, and there are anonymous inner classes. In all cases though, they behave just the same. They still need to be instantiated, and they still contain variables and methods. What we will look at here is what those different types are, and when you might use them.

To do this, we will once again revisit the Robot. This time we will be adding a head that rotates to the Robot. We will look at placing the code directly into the Robot without using another class, using an inner class to Robot, and using containment to hold another class.

Before we get to that, lets revisit the parent/child relationship that exists when a class is extended and how casting works. Then we will get to the RobotHead.
Sun Trails Index: http://java.sun.com/docs/books/tutorial/index.html
Link into Objects and Classes Trail: (nested classes) http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html

Revisiting extending

/**
 * Our basic Robot object we will be dealing with.
 * 
 * @author veggie2u@cyberward.net
 */
public class Robot extends Object {

   private int location;
	
   public static final String MODEL_NUMBER = "XRT354";
	
   public Robot() {
      System.out.println("I am a Robot.");
   }
	
   public int getLocation() {
      return location;
   }
	
   public void moveUp() {
      location = location + 1;
   }
	
   public void moveDown() {
      location = location - 1;
   }
}
/**
 * We are extending Robot here. This is just a simple extension to look at how
 * that works. We want to look at constructor beheviour, as well as method
 * overriding.
 * 
 * @author veggie2u@cyberward.net
 */
public class Robot5 extends Robot {

   // Does this MODEL_NUMBER hide the Robot version? Not when it is static and
   // used staticly. If you access it via Robot.MODEL_NUMBER and
   // Robot5.MODEL_NUMBER they are completely seperate. Accessing via an
   // instance, which is not recommended, is a little different. It will
   // return the correct model number for the robot type that was created.
   public static final String MODEL_NUMBER = "WALL45E";

   private String name;

   /**
    * What does this constructor do? What is 'this' used for? Is this a good
    * convention to follow?
    */
   public Robot5() {
      this("Wall-E");
   }

   /**
    * This is not a constructor that Robot has. Is this a problem? Look here at
    * the super(). What is is doing? What all with this method do when
    * executed?
    * 
    * @param pName
    */
   public Robot5(String pName) {
      // What's so super? What is it doing?
      super();
      setName(pName);
      System.out.println(pName + " was created.");
   }

   public String getName() {
      return name;
   }

   public void setName(String pName) {
      name = pName;
   }
	
   /**
    * What does this mean haveing the same method name as Robot?
    */
   public int getLocation() {
      // why can't we see location? What change could we make to see it?
      // return location * 2;

      // what is 'super' doing here?
      return super.getLocation() * 2;
   }
}

Lets look at Robot5. Robot5 extends Robot. This means that we are taking the functionality of Robot, and adding new functionality to it. This is called extending. When we create a Robot5, by doing a “new”, we call constructors on Robot5. When we create a Robot5 we should look after the parent class, or the Robot, that we extended. We do this by calling super() inside the constructor on the first line. We want to do this to make sure that Robot gets set up just like the creator of Robot intended. So take a look at RobotTesta. This is a very simple test that shows the creation of two Robot5 classes. Take a look at what gets printed when this test runs. We have system.out.println statements in Robot, Robot5, and the test class. We want to understand what gets printed and when. Even better, start up the eclipse debugger, but a breakpoint on the first line of RobotTest5 and watch how it all works.

/**
 * Take a look at how the robots are created (instantiated). What constructors
 * are being used when? Does a constructor on the parent class (Robot) get
 * called?
 * 
 * @author veggie2u@cyberward.net
 */
public class RobotTesta {

   public static void main(String[] args) {

      Robot5 bob = new Robot5();
      System.out.println("My name is " + bob.getName());

      Robot5 doug = new Robot5("doug");
      System.out.println("My name is " + doug.getName());
   }
}

What is a Robot?

When one class extends another, we say that it’s a “is a” relationship. Therefore, Robot5 is a Robot. The reverse is not true however. Robot is not a Robot5. What this means is that Robot5 has all the function and ability of Robot. But Robot does not have all the functionality of Robot5. We know already that Robot does not have a name attribute. Robot5 does. Thinking in these terms it is more obvious that Robot is not a Robot5.

Is there a way we use this in Java? What we will look at here is casting. Next lesson we will look at interfaces. Casting is taking an object and manipulating it as if it was a parent class.

  1. 1. Robot doug = new Robot5(“doug”);
  2. 2. Robot5 doug5 = (Robot5) doug;
  3. 3. Robot bob = (Robot)doug5;

The first line does an implicit cast. First a Robot5 is created, then it is assigned to a Robot that we called doug. This works, because Robot5 is a Robot. The second line works to cast doug, a Robot to a Robot5 because doug really is a Robot5. That is how this object was created. The third line casts doug5 to a Robot again, assigning it to bob. Take a look at RobotTestb. It is well commented.

Lets revisit line 2 and see when it works. If we look at these two lines:

Robot walle = new Robot();
Robot5 walle5 = (Robot5)walle;

This compiles, because the compiler has a hard time knowing what type of class walle will be at runtime. We can’t cast a type Robot to a type Robot5. Java wouldn’t know what to do with the name from Robot5 for example. A Robot is not a Robot 5. When we run this we get a “java.lang.ClassCastException”. Java can only determine this at runtime. Line 2 from above is similar to our walle example. But it works on line 2 because the object that is held in doug is a Robot5 in memory. Therefore it is able to be cast from doug’s type definition of Robot to doug5’s type definition of a Robot5.

It is important to be able to understand what is a what, and when you can cast from one type to another. Next lesson when we talk about interfaces we will build on this idea.

/**
 * Take a look at the relationship between Robot and Robot5. What statement is
 * true? Robot "is a" Robot5. Robot5 "is a" Robot.
 * 
 * @author veggie2u@cyberward.net
 */
public class RobotTestb {

   public static void main(String[] args) {

      // A Robot5 is created, and stored as a Robot
      Robot doug = new Robot5("doug");
      // Why does this line not work? Isn't it a method on Robot5?
      // System.out.println("My name is " + doug.getName());

      // doug, the Robot, is cast to a Robot5. This works becuase he was
      // created as a Robot5.
      Robot5 doug5 = (Robot5) doug;
      System.out.println("My name is " + doug5.getName());

      Robot bob = (Robot) doug5;
      // why can't we set Robot bob's name? isn't bob really doug5, a Robot5
      // bob.setName("bob");
      Robot5 bob5 = (Robot5) bob;
      bob5.setName("bob");
      System.out.println("(bob5) My name is " + bob5.getName());

      // What name get's printed from this line? Why that name?
      System.out.println("(doug5) My name is " + doug5.getName());

      // Try uncommenting these lines. Why does it compile, but not run?
      // Robot walle = new Robot();
      // Robot5 walle5 = (Robot5)walle;
   }
}

Method Overriding

Another thing that is important to understand when a class is extended, is method overriding. This means that we implement the exact same method in the child class as already exists in the parent. In our examples, that means implementing the getLocation() method in Robot5 that already exists in Robot. (Note: in eclipse you see a green up facing arrow beside the method signature)

If we have a Robot5 created like this:

Robot5 bob5 = new Robot5();

We can call a Robot method on it such as bob5.moveUp(). We can call a Robot5 method such as bob5.getName(). What about bob5.getLocation()? Is it a Robot, or a Robot5 method? It is a Robot5 method. When we call bob5.getLocation() we are calling the method in Robot5. The Robot method is partially hidden. How could we get to it? Similar to what we did in the constructor to call the parents constructor. In this case, like we did in the Robot5 getLocation() method, it is super.getLocation(). This causes the method that was defined by Robot to be called. Why would we do this? Remember, we often extend a class to add functionality, so we may want to do everything that the Robot method does, but add something, or do it just a little differently. That is what we do in Robot5. Here we return two times the value of the location, in a sense making the Robot5 appear to move twice as far as a Robot would.

There is nothing in java that says you need to do the same or similar things because you have the same method names. We could have coded this:

public int getLocation() {
   return new Date().hashCode();
}

This has nothing to do with location. You could do it, but you wouldn’t want to. It could really mess things up for you or someone else in the future. You might think you can keep the difference straight now, but here is an example why that is not quite so obvious.

Robot doug = new Robot5("doug");
System.out.println("location:"+doug.getLocation());

We created a Robot5 object, and hold it in memory in a Robot type called doug. When we call doug.getLocation(), what method did it run? The getLocation() method from Robot, or Robot5? Actually, the one from Robot5. So, if you override a method, make sure the reason is to augment the method from the child class, not to change the reason the method was created in the first place.

Let’s find our Robot a Head

Time to move on. Our robot needs to gain some functionality. We have decided to give our Robot a head, and the ability to turn the head, and look around. How should we do this? There are a few ways to organize this code. Let’s look at how we could do it.

  1. 1. Put all the new code into the Robot class.
  2. 2. Create a separate class called RobotHead to hold the code.
  3. 3. Insert an inner class with the robot head code in it into Robot.

Number 1.

/**
 * Another example of extending a class. Now we extend Robot to add more
 * functionality. We are adding the functionality of a robot head. There are
 * things to think about here. Does it make sense to put the code here in this
 * class? Would there be a benefit to moving this code to another class?
 * 
 * @author veggie2u@cyberward.net
 */
public class Robot6 extends Robot {

   // hold the number of degrees to change when moving the head
   private static final int STEP = 45;

   private static final String[] LOOKING_DIRECTION = new String[] {
            "Looking North East", "Looking East", "Looking South East",
            "Looking South", "Looking South West", "Looking West",
            "Looking North West", "Looking North" };

   // hold the position of the head
   private int degrees;

   /**
    * Initialize the RobotHead to be pointing North
    */
   public Robot6() {
      this(360);
   }

   /**
    * Initialize the RobotHead to a starting position. Note that we really only
    * want values divisible by 45 here and are not protected by setting some
    * other value. In "real life" you would need to do that.
    */
   public Robot6(int pDegrees) {
      super();
      degrees = pDegrees;
   }

   public void turnClockwise() {
      changeDegrees(STEP);
   }

   public void turnCounterClockwise() {
      changeDegrees(-STEP);
   }

   /**
    * Private method that does the moving of the head. It makes sure that the
    * degrees are within the parameters of 0-360
    * 
    */
   private void changeDegrees(int pAmountOfChange) {
      degrees += pAmountOfChange;
      if (degrees <= 0) {
         degrees = 360 + degrees;
      } else if (degrees > 360) {
         degrees = degrees - 360;
      }
   }

   /**
    * Return the position of the RobotHead in degrees (as an int)
    * 
    */
   public int getDegrees() {
      return degrees;
   }

   /**
    * Return the direction the RobotHead is looking.
    * 
    */
   public String look() {
      int aPosition = (int) Math.floor(degrees / 45) - 1;
      return LOOKING_DIRECTION[aPosition];
   }
}

Option one is really the same as what we did with Robot5 before. We extended Robot to gain some functionality. Let’s do that with Robot6. Here we extend Robot with the functionality to turn the head clockwise, or counter clockwise, and look in the direction the head is facing. RobotTestc simply verifies that it is working.

/**
 * Simple test class for Robot6. Just to prove that the class had the robot head
 * functionality, and that it works.
 * 
 * @author veggie2u@cyberward.net
 */
public class RobotTestc {

   public static void main(String[] args) {

      Robot6 bob = new Robot6();
      System.out.println(bob.look());
      bob.turnClockwise();
      bob.turnClockwise();
      System.out.println(bob.look());
   }
}

Do we like this way of organizing our code? It took quite a few lines of code, the code for the robot head is not self contained in any way, which could make maintenance more difficult, and it means that no other classes can use this functionality without copying code.

Number 2.

/**
 * This is the RobotHead in a seperate class. This class provides the
 * functionality of turning the head left and right, and looking in the
 * direction it is turned in. It was created to have a class that would add
 * functionality to the Robot.
 * 
 * @author veggie2u@cyberward.net
 */
public class RobotHead {

   // hold the number of degrees to change when moving the head
   private static final int STEP = 45;

   private static final String[] LOOKING_DIRECTION = new String[] {
            "Looking North East", "Looking East", "Looking South East",
            "Looking South", "Looking South West", "Looking West",
            "Looking North West", "Looking North" };

   // hold the position of the head
   private int degrees;

   /**
    * Initialize the RobotHead to be pointing North
    */
   public RobotHead() {
      this(360);
   }

   /**
    * Initialize the RobotHead to a starting position. Note that we really only
    * want values divisible by 45 here and are not protected by setting some
    * other value. In "real life" you would need to do that.
    * 
    */
   public RobotHead(int pDegrees) {
      degrees = pDegrees;
   }

   /**
    * Turn the RobotHead one STEP clockwise
    */
   public void turnClockwise() {
      changeDegrees(STEP);
   }

   /**
    * Turn the RobotHead one STEP counter clockwise
    */
   public void turnCounterClockwise() {
       changeDegrees(-STEP);
   }

   /**
    * Private method that does the moving of the head. It makes sure that the
    * degrees are within the parameters of 0-360
    * 
    */
   private void changeDegrees(int pAmountOfChange) {
      degrees += pAmountOfChange;
      if (degrees <= 0) {
         degrees = 360 + degrees;
      } else if (degrees > 360) {
         degrees = degrees - 360;
      }
   }

   /**
    * Return the position of the RobotHead in degrees (as an int)
    * 
    */
   public int getDegrees() {
      return degrees;
   }

   /**
    * Return the direction the RobotHead is looking.
    */
   public String look() {
      int aPosition = (int) Math.floor(degrees / 45) - 1;
      return LOOKING_DIRECTION[aPosition];
   }
}
/**
 * This just shows the functionality of the RobotHead
 * 
 * @author veggie2u@cyberward.net
 */
public class RobotHeadTesta {

    public static void main(String[] args) {

      RobotHead aHead = new RobotHead();

      for (int i = 0; i < 40; i++) {
         aHead.turnClockwise();
         System.out.print("degrees:" + aHead.getDegrees());
         System.out.println(", " + aHead.look());
      }
   }
}
/**
 * Again we are extending Robot to add the RobotHead functionality, but this
 * time we make it a seperate class. There are things to think about here. Don't
 * we expose RobotHead here for someone to mess it up? What if they set it to
 * null? Doesn't this structure mean that they have to intimate knowledge of
 * RobotHead to make it work? eg., to turn or look, the using class first has to
 * request the RobotHead object, then perform the method on it. What happens if
 * in maintenance we change RobotHead a bit, or decide to use RobotHead2
 * instead. Now all classes that used us are broken if they relied on this
 * method.
 * 
 * @author veggie2u@cyberward.net
 */
public class Robot7 extends Robot {

   private RobotHead robotHead;

   public Robot7() {
      super();
      robotHead = new RobotHead();
   }

   public void setRobotHead(RobotHead pRobotHead) {
      robotHead = pRobotHead;
   }

   public RobotHead getRobotHead() {
      return robotHead;
   }
}

Can we improve upon this? Let us move the robot head code into a new class called RobotHead. There is a test program RobotHeadTesta to verify that just this code is working. This RobotHead is now implemented in Robot7. When we place a class within another like this, it is called containment. So, how did we do? We moved the code to a self contained object. Now it is easier for maintenance, and other classes could implement the RobotHead too. Sounds good. Does our implementation work?

/**
 * Simple test class for Robot7. Just to prove that the class had the robot head
 * functionality, and that it works.
 * 
 * @author veggie2u@cyberward.net
 */
public class RobotTestd {

   public static void main(String[] args) {

      Robot7 bob = new Robot7();
      System.out.println(bob.getRobotHead().look());
      bob.getRobotHead().turnClockwise();
      bob.getRobotHead().turnClockwise();
      System.out.println(bob.getRobotHead().look());
   }
}

Well, we still have some problems. With a set method, someone could set the robot head to null, which wouldn't be a good idea unless we were blowing our robot's head off. We could just take out the set method, we do initialize the RobotHead in the constructor. Are we good? Well, there are still problems. The way we have implemented, someone has to first ask for the robot head, then execute a method on it. This means that they have to have intimate knowledge of how to use RobotHead, not just Robot7. Also, what happens in the future if we want to use RobotHead2 in Robot7? The getRobotHead() method would have to change to return the RobotHead2 type, and now all the code that used Robot7 is broken. Hmm....

Number 2 try again.

/**
 * Again we are extending Robot to add the RobotHead functionality, but this
 * time we make it a seperate class. There are things to think about here. Why
 * didn't we just put the RobotHead code right in this class? Don't we just have
 * 3 extra methods here? What would the benefits of using an external class like
 * this be?
 * 
 * After looking at this example, lets say we have been asked to modify Robot8
 * to use the new and improved RobotHead2. Switch around the commented code to
 * see what you would need to do to make the switch. Because our robot head,
 * either RobotHead or RobotHead2 is completely contained within this class, we
 * didn't need to modify any classes that used Robot8. We would have had lots to
 * change if we had done with with Robot7.
 * 
 * @author veggie2u@cyberward.net
 */
public class Robot8 extends Robot {

   private RobotHead robotHead;
   // private RobotHead2 robotHead;

   public Robot8() {
      super();
      robotHead = new RobotHead();
      // robotHead = new RobotHead2();
   }

   public void turnClockwise() {
      robotHead.turnClockwise();
      // robotHead.turnRight();
   }

   public void turnCounterClockwise() {
      robotHead.turnCounterClockwise();
      // robotHead.turnLeft();
   }

   public String look() {
      return robotHead.look();
   }
}
/**
 * Simple test class for Robot8. Just to prove that the class had the robot head
 * functionality, and that it works.
 * 
 * @author veggie2u@cyberward.net
 */
public class RobotTeste {

   public static void main(String[] args) {

      Robot8 bob = new Robot8();
      System.out.println(bob.look());
      bob.turnClockwise();
      bob.turnClockwise();
      System.out.println(bob.look());
   }
}

Let's leave RobotHead as is. Let's modify our implementation to what is in Robot8. What we have done here is to only expose the methods of RobotHead that we want people to access from Robot8. We could have exposed all of them, and maybe at some point as features grow we will have to. So, we create a RobotHead in the constructor, and then create methods for access. We have turnClockwise(), turnCounterClockwise(), and look() methods. Does this seem like just extra work? In a way I agree that it is some extra work, but it has contained the RobotHead class completely to Robot8. If we want to see how well containment has worked here, let's pretend that we have been asked to implement the new and improved RobotHead2. Robot8 can be modified by swapping lines of code with the commented ones. We have now refactored Robot8 to modify it, and we didn't have to modify any class that uses Robot8.

/**
 * This is really just RobotHead where the LOOKING DIRECTION values have been
 * changed and the turn method names have changed. This is just an example to
 * show how Robot8 might be 'upgraded' in the future, and how we would have to
 * deal with it.
 * 
 * @author veggie2u@cyberward.net
 */
public class RobotHead2 {

   // hold the number of degrees to change when moving the head
   private static final int STEP = 45;

   private static final String[] LOOKING_DIRECTION = new String[] {
            "Looking toward the North East", "Looking toward the East",
            "Gazing South East", "Gazing South", "Gazing South West",
            "Scanning the West", "Scanning North West", "Observing North" };

   // hold the position of the head
   private int degrees;

   /**
    * Initialize the RobotHead to be pointing North
    */
   public RobotHead2() {
      this(360);
   }

   /**
    * Initialize the RobotHead to a starting position. Note that we really only
    * want values divisible by 45 here and are not protected by setting some
    * other value. In "real life" you would need to do that.
    * 
    * @param pDegrees
    */
   public RobotHead2(int pDegrees) {
      degrees = pDegrees;
   }

   /**
    * Turn the RobotHead one STEP clockwise
    */
   public void turnRight() {
      changeDegrees(STEP);
   }

   /**
    * Turn the RobotHead one STEP counter clockwise
    */
   public void turnLeft() {
      changeDegrees(-STEP);
   }

   /**
    * Private method that does the moving of the head. It makes sure that the
    * degrees are within the parameters of 0-360
    */
   private void changeDegrees(int pAmountOfChange) {
      degrees += pAmountOfChange;
      if (degrees <= 0) {
         degrees = 360 + degrees;
      } else if (degrees > 360) {
         degrees = degrees - 360;
      }
   }

   /**
    * Return the position of the RobotHead in degrees (as an int)
    */
   public int getDegrees() {
      return degrees;
   }

   /**
    * Return the direction the RobotHead is looking.
    */
   public String look() {
      int aPosition = (int) Math.floor(degrees / 45) - 1;
      return LOOKING_DIRECTION[aPosition];
   }
}

Number 3 Inner Class

/**
 * This time we are extending Robot to add the RobotHead functionality, but this
 * time we make it an inner class. There are things to think about here. Why
 * didn't we just put the RobotHead code right in the main class? Don't we just
 * have 3 extra methods here? What would the benefits of using an inner class
 * like this be? Isn't this is worst of all worlds? The code in inside this one
 * class, but we still have extra methods?
 * 
 * @author veggie2u@cyberward.net
 */
public class Robot9 extends Robot {

   private RobotHead robotHead;

   public Robot9() {
      super();
      robotHead = new RobotHead();
   }

   public void turnClockwise() {
      robotHead.turnClockwise();
   }

   public void turnCounterClockwise() {
      robotHead.turnCounterClockwise();
   }

   public String look() {
      return robotHead.look();
   }

   public class MyRobotHead {

      // hold the number of degrees to change when moving the head
      private static final int STEP = 45;

      // note that lookingDirection can't be static in this inner class
      private final String[] lookingDirection = new String[] {
               "Looking North East", "Looking East", "Looking South East",
               "Looking South", "Looking South West", "Looking West",
               "Looking North West", "Looking North" };

      // hold the position of the head
      private int degrees;

      /**
       * Initialize the RobotHead to be pointing North
       */
      public MyRobotHead() {
         this(360);
      }

      /**
       * Initialize the RobotHead to a starting position. Note that we really
       * only want values divisible by 45 here and are not protected by
       * setting some other value. In "real life" you would need to do that.
       * 
       * @param pDegrees
       */
      public MyRobotHead(int pDegrees) {
         degrees = pDegrees;
      }

      /**
       * Turn the RobotHead one STEP clockwise
       */
      public void turnClockwise() {
         changeDegrees(STEP);
      }

      /**
       * Turn the RobotHead one STEP counter clockwise
       */
      public void turnCounterClockwise() {
         changeDegrees(-STEP);
      }

      /**
       * Private method that does the moving of the head. It makes sure that
       * the degrees are within the parameters of 0-360
       * 
       * @param pAmountOfChange
       */
      private void changeDegrees(int pAmountOfChange) {
         degrees += pAmountOfChange;
         if (degrees <= 0) {
            degrees = 360 + degrees;
         } else if (degrees > 360) {
            degrees = degrees - 360;
         }
      }

      /**
       * Return the position of the RobotHead in degrees (as an int)
       */
      public int getDegrees() {
         return degrees;
      }

      /**
       * Return the direction the RobotHead is looking.
       */
      public String look() {
         int aPosition = (int) Math.floor(degrees / 45) - 1;
         return lookingDirection[aPosition];
      }
   }
}
/**
 * Simple test class for Robot9. Just to prove that the class had the robot head
 * functionality, and that it works.
 * 
 * @author veggie2u@cyberward.net
 */
public class RobotTestf {

   public static void main(String[] args) {

      Robot9 bob = new Robot9();
      System.out.println(bob.look());
      bob.turnClockwise();
      bob.turnClockwise();
      System.out.println(bob.look());
   }
}

This isn't really a progression. Number 2 finished off pretty well, but I want to use the same code to show what an inner class looks like. An inner class is simply a class that is defined inside another class. Let's look at Robot9 and RobotTestf. Here we have moved all the RobotHead code back into the Robot9 class, but moved it into an inner class. It looks kind of like both Robot6 and Robot8 combined. We have all the code for the RobotHead inside the Robot9 class (just like Robot6), but it is in a class and we access the head like Robot8 did. Looks like the worst of both worlds? This is not a good example of how to use an inner class. I just wanted it here for comparison.

/**
 * Example of an class that contains an inner class. When can external programs
 * use or not use the inner class? When would you want to use an inner class?
 * 
 * @author veggie2u@cyberward.net
 */
public class OuterClass {

   private String seperator = ", ";
   private InnerClass innerClass;

   public OuterClass() {
      innerClass = new InnerClass();
   }

   public String getName() {
      return innerClass.getName();
   }

   /**
    * Here is the inner class. It is defined and used in much the same way as a
    * regular class is. The exception here is that the outer class must be
    * instantiated before you can use the inner class. What effect does the
    * modifier public have on our inner class? See OuterClassTesta.java.
    */
   public class InnerClass {

      private String firstName = "Chris";
      private String lastName = "Ward";

      public String getName() {
         return lastName + seperator + firstName;
      }
   }
}
/**
 * Test for OuterClass and InnerClass. This is to see the relationships between
 * them. Notice how we can create an instance of the inner class from our
 * outerClass instance. If you didn't want this to be done, and only wanted this
 * inner class to be restricted to OuterClass, what could you do?
 * 
 * @author veggie2u@cyberward.net
 */
public class OuterClassTesta {

   public static void main(String[] args) {

      OuterClass outerClass = new OuterClass();
      System.out.println(outerClass.getName());

      InnerClass innerClass = outerClass.new InnerClass();
      System.out.println(innerClass.getName());
   }
}

I have another example of an inner class called OuterClass (with an inner class cleverly named InnerClass). This is a smaller section of code, and we can use it to see a couple of things.

One thing to take away from this is that the inner class can not be used, or instantiated unless the outer class has been instantiated. (Note: If the inner class is static, the outer class does not need to be instantiated, but an inner static class is not recommended. It can likely be a standalone class.) Take a look at OuterClassTesta and you will see a strange line 21. We can instantiate the InnerClass with the code:

InnerClass innerClass = outerClass.new InnerClass();

The brings up two issues. The first is we need an OuterClass instance, the second is visibility. Why can we even use this class outside of OuterClass? It is marked as public. Normally you need your class to be public, or you can't use it at all. In the case of inner classes, we can indicate that they are private. Then they are only available to the outer class, and not externally.

You may be wondering why we bother. Inner classes don't appear to be all that useful. One thing that we haven't talked about is that you can use instance variables from the outer class in the inner class. If you look back at OuterClass we have done that with the separator field. This is a good thing to remember. If we had created an external class this obviously would not be possible. The times that inner classes make sense usually involve an interface or a base class that you partially implement. We will return to the idea of an inner class further after looking at interfaces, but let's use some GUI programming to look a bit more at inner classes.

Simplest GUI program ever

/**
 * Simpliest program to create a window frame using swing.
 * 
 * Note, closeing this program doesn't actually close it, just hides the window.
 * 
 * @author veggie2u@cyberward.net
 */
public class Gui1 extends JFrame {

   public Gui1() {
      setTitle("Gui1");
      setSize(300, 300);
   }

   public static void main(String[] args) {
      JFrame aFrame = new Gui1();
      aFrame.setVisible(true);
   }
}

Take a look at Gui1. This is about the simplest GUI program you can create. It simply puts a JFrame on the screen with a title and a set size.

A problem with this is that there is no way to exit the Gui1 program. You can close the window, but when you do that, your program actually continues. We need to fix that. The normal way to do this is to create a class that extends WindowAdapter and call addWindowListener() on our JFrame.

/**
 * Simple program to create a window frame and demonstrate using an inner class
 * to close the frame. This is a better example of using an inner class than
 * Robot9. Here, WindowCloser is a class that will only be used by Gui2, and it
 * requires implementing an interface or abstract class to make it work.
 * 
 * @author veggie2u@cyberward.net
 */
public class Gui2 extends JFrame {

   public Gui2() {
      setTitle("Gui2");
      setSize(300, 300);
      addWindowListener(new WindowCloser());
      // Above line is the same as the next two
      // WindowCloser aCloser = new WindowCloser();
      // addWindowListener(aCloser);
      // There is no reason to keep a reference to this object, so we don't
      // bother to keep one.
   }

   /**
    * In order to add a window listener, we need a class that implements the
    * WindowListener interface. That interface requires 7 different methods to
    * be created. For our example here, we will instead extend WindowAdapter
    * which is an abstract class that implements all of these methods for us.
    */
   public class WindowCloser extends WindowAdapter {

      // The only method that we really need to implement to handle the
      // closing of the window is this one.
      public void windowClosing(WindowEvent e) {
         System.out.println("Closeing window titled: " + getTitle());
         // notice that as an inner class we can call the getTitle() method
         // from the outer class
         System.exit(0);
      }
}

   public static void main(String[] args) {
      JFrame aFrame = new Gui2();
      aFrame.setVisible(true);
   }
}

Gui2 does this. There are only two additions to Gui1. In the Gui2 constructor we add one line:

addWindowListener(new WindowCloser());

WindowCloser is a class that I made. Just happens to be an inner class. I don't intend to use it on any other program, or maybe it is very specific to this program. Either way, I decided to create it as an inner class. In order to use the addWindowListener() method, I need to create a class that implements the WindowListener interface. Just so happens that the WindowAdapter class does this, and we can extend it. So all I need to do is create a small inner class to handle the particular event I want to deal with.

Now we start to see where the inner class becomes useful. The code created is only going to be used here in this class. It is just a small class that is doing one small specific thing, and in this case happens to use a method from the enclosing (outer) class. A great time to create an inner class.

/**
 * Simple program to create a window frame and demonstrate using an annonymous
 * inner class to close the frame. This is a better way even than Gui2. There is
 * no real reason to have a concrete class. We don't need the reference to the
 * WindowCloser class, so lets not bother with defining one. Let's just create
 * an annonymous inner class.
 * 
 * @author veggie2u@cyberward.net
 */
public class Gui3 extends JFrame {

   public Gui3() {
      setTitle("Gui3");
      setSize(300, 300);
      // We create a WindowAdapter class, and inline, override the
      // windowClosing method. This way we don't need to create an external or
      // inner class for "WindowCloser"
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
            System.out.println("Closeing Gui3");
            System.exit(0);
         }
      });
   }

   public static void main(String[] args) {
      JFrame aFrame = new Gui3();
      aFrame.setVisible(true);
   }
}

Well, how about an anonymous inner class. A what? Just what it sounds like. A class with no name. Gui3 takes the inner class concept one step further. Not only is the WindowCloser class only going to be used in this one class, it is only going to be called by one method. In that case we can avoid creating a reference for it, and do something like this:

addWindowListener(new WindowAdapter() {
   public void windowClosing(WindowEvent e) {
      System.out.println("Closeing Gui3");
      System.exit(0);
   }
});

It may look a little strange, but it did exactly the same thing as in Gui2. Only difference is that we no longer have a named inner class. We have an anonymous inner class that we define right as we set out object when we called the addWindowListener() method.

The is by far the most common way you will see anonymous inner classes used. They are used all over the Swing packages like this. When you are creating button listeners or other event handlers, this is the typical pattern you will use. You will also see an inner class sometimes defined this way if you are going to use it more than once:

private WindowListener windowCloser = new WindowAdapter() {
   public void windowClosing(WindowEvent e) {
      System.out.println("Closeing Gui3");
      System.exit(0);
   }
};

This way you have a reference to your code already, and you can assign it to several listeners if you need to. This isn't used as often.

[drain file 6 show tableRow]

[drain file 7 show tableRow]

Type Download Name Version Size Updated Hits
Series NavigationIntro to Java and Static StuffIntro to Java Interfaces