WebReference.com - Part 5 of chapter 5 from Beginning Java 2 SDK 1.4 Edition, Wrox Press Ltd (2/6) | WebReference

WebReference.com - Part 5 of chapter 5 from Beginning Java 2 SDK 1.4 Edition, Wrox Press Ltd (2/6)

To page 1current pageTo page 3To page 4To page 5To page 6
[previous] [next]

Beginning Java 2 SDK 1.4 Edition

Static Nested Classes

To make objects of a nested class type independent of objects of the enclosing class, you can declare the nested class as static. For example,

public class Outside {
  public static class Skinside {
    // Details of Skinside
  }
  // Nested class
  public class Inside {
    // Details of Inside class...
  }
  // More members of Outside class...
}

Now with Skinside inside Outside declared as static, we can declare objects of this nested class, independent from objects of Outside, and regardless of whether we have created any Outside objects or not. For example:

non-static vs. static nested classes

Let's see how a nested class works in practice with a simple example. We will create a class MagicHat that will define an object containing a variable number of rabbits. We will put the definition for the class Rabbit inside the definition of the class MagicHat. The basic structure of MagicHat.java will be:

public class MagicHat {
  // Definition of the MagicHat class...
  // Nested class to define a rabbit
  static class Rabbit {
    // Definition of the Rabbit class...
  }
}

Here the nested class is defined as static because we want to be able to have static members of this class. We will see a little later how it might work with a non-static nested class.

Try It Out--Rabbits Out of Hats

Let's add the detail of the MagicHat class definition:

import java.util.Random;                      // Import Random class
public class MagicHat {
  static int maxRabbits = 5;                  // Maximum rabbits in a hat  
  static Random select = new Random();        // Random number generator   
                                                                           
  // Constructor for a hat                                                 
  public MagicHat(String hatName) {                                        
    this.hatName = hatName;                   // Store the hat name        
    rabbits = new Rabbit[1+select.nextInt(maxRabbits)]; // Random rabbits  
                                                                           
    for(int i = 0; i < rabbits.length; i++)                                
      rabbits[i] = new Rabbit();              // Create the rabbits        
  }                                                                        
                                                                           
  // String representation of a hat                                        
  public String toString() {                                               
    // Hat name first...                                                   
    String hatString = "\n" + hatName + " contains:\n";                    
                                                                           
    for(int i = 0; i < rabbits.length; i++)                                
      hatString += "\t" + rabbits[i] + " ";   // Add the rabbits strings   
    return hatString;                                                      
  }                                                                        
                                                                           
  private String hatName;                     // Name of the hat           
  private Rabbit rabbits[];                   // Rabbits in the hat        

  // Nested class to define a rabbit
  static class Rabbit {
    // Definition of the Rabbit class...
  }
}

Instead of the old Math.random() method that we have been using up to now to generate pseudo-random values, we are using an object of the class Random that is defined in the package java.util. An object of type Random has a variety of methods to generate pseudo-random values of different types, and with different ranges. The method nextInt() that we are using here returns an integer that is zero or greater, but less than the integer value you pass as an argument. Thus if you pass the length of an array to it, it will generate a random index value that will always be legal for the array size.

We can now add the definition of the Rabbit class. When we create a Rabbit object, we want it to have a unique name so we can distinguish one Rabbit from another. We can generate unique names by selecting one from a limited set of fixed names, and then appending an integer that is different each time the base name is used. Here's what we need to add for the Rabbit class definition:

public class MagicHat {
  // Definition of the MagicHat class--as before...
  // Nested class to define a rabbit
  static class Rabbit {
    // A name is a rabbit name from rabbitNames followed by an integer           
    static private String[] rabbitNames = {"Floppsy", "Moppsy",                  
                                           "Gnasher", "Thumper"};                
    static private int[] rabbitNamesCount = new int[rabbitNames.length];         
    private String name;                             // Name of the rabbit       
                                                                                 
    // Constructor for a rabbit                                                  
    public Rabbit() {                                                            
      int index = select.nextInt(rabbitNames.length);  // Get random name index  
      name = rabbitNames[index] + (++rabbitNamesCount[index]);                   
    }                                                                            
                                                                                 
    // String representation of a rabbit                                         
    public String toString() {                                                   
      return name;                                                               
    }
  }
}

Note that the constructor in the Rabbit class can access the select member of the enclosing class MagicHat, without qualification. This is only possible with static members of the enclosing class--you can't refer to non-static members of the enclosing class here because there is no object of type MagicHat associated with it.

We can use the following application class to try out our nested class:

public class TryNestedClass {
  static public void main(String[] args) {
    // Create three magic hats and output them
    System.out.println(new MagicHat("Gray Topper"));
    System.out.println(new MagicHat("Black Topper"));
    System.out.println(new MagicHat("Baseball Cap"));
  }
}

When I ran the program, I got the output:

Gray Topper contains:
	Moppsy1 	Moppsy2 	Floppsy1 
Black Topper contains:
	Thumper1 	Moppsy3 	Thumper2 	  Gnasher1 
Baseball Cap contains:
	Moppsy4 	Moppsy5 	Thumper3

You are likely to get something different.

How it Works

Each MagicHat object will contain a random number of Rabbit objects. The constructor for a MagicHat object stores the name of the hat in its private member hatName, and generates a Rabbit array with at least one, and up to maxRabbits elements. This is done with the expression 1+select.nextInt(maxRabbits). Calling nextInt() with the argument maxRabbits will return a value that is from 0 to maxRabbits-1 inclusive. Adding 1 to this will result in a value from 1 to maxRabbits inclusive. The array so created is then filled with Rabbit objects.

The MagicHat class also has a method toString() method which returns a String object containing the name of the hat and the names of all the rabbits in the hat. This assumes that the Rabbit class also has a toString() method defined. We will be able to use the toString() implicitly in an output statement when we come to create and display MagicHat class objects.

The base names that we use to generate rabbit names are defined in the static array rabbitNames[] in the Rabbit class. The count for each base name, which we will append to the base name to produce a unique name for a rabbit, is stored in the static array rabbitNamesCount[]. This has the same number of elements as the rabbitNames array, and each element stores a value to be appended to the corresponding name in the rabbitNames array. The Rabbit class has the data member, name, to store a name that is initialized in the constructor. A random base name is selected from the rabbitNames[] array using an index value from 0 up to one less than the length of this array. We then append the current count for the name incremented by 1, so successive uses of any base name such as Gnasher, for example, will produce names Gnasher1, Gnasher2, and so on. The toString() method for the class returns the name for the Rabbit object.

The method main() in TryNestedClass creates three MagicHat objects and outputs the string representation of each of them. Putting the object as an argument to the println() method will call the toString() method for the object automatically, and the String object that is returned will be output to the screen.


To page 1current pageTo page 3To page 4To page 5To page 6
[previous] [next]

Created: August 5, 2002
Revised: August 5, 2002

URL: https://webreference.com/programming/java/beginning/chap5/5/2.html