Intro to Java and Static Stuff

This lesson will cover some basic concepts in Java related to static variables and methods. It was created as a lesson for a class room setting. I have converted it to a post here.

What does static mean?

Lucky for us, static has nothing to do with statics, a class I had to take in Engineering about the forces on objects that are not moving.

What is does have to do with, seems to go against the concepts we talked about in the Classes vs. Objects lesson. If you followed along there, we talked about how the Class was the blueprint, and the Object was a concrete, instantiated, “built” Class. Its variables were its own, and the methods belonged to this Object.

When something is static, it means that it belongs to the class, and not the object. Every object has access to this item, but it is not unique to the object.

Sun Trails

Index: http://java.sun.com/docs/books/tutorial/index.html

Link into OO Trail: http://java.sun.com/docs/books/tutorial/java/javaOO/classvars.html

Let’s look at how you create instance and static variables

public class Robot extends Object {

   private int location;

   /**
    * Static member variable - who does this belong to?
    */
   public static final String MODEL_NUMBER = "XRT354";

   public Robot() {
      System.out.println("Robot created.");
   }

   /**
    * Static method call - how does this get called?
    */
   public static String getModelNumber() {
      return MODEL_NUMBER;
   }

   public int getLocation() {
      return location;
   }

   public void moveUp() {
      location = location + 1;
   }

   public void moveDown() {
      location = location - 1;
   }

   /**
    * The method "main" isn't magic, it is just a static method like the
    * getModelNumber() method. The big difference is that this is the class
    * that will be executed if you "run" a java program. It is the method that
    * it looked for by java. Java will also populate the "args" array with
    * Strings passed to it if you ran the program from the command line. (See
    * RobotTestb)
    */
   public static void main(String[] args) {

      // By calling this class, we don't have a bob (robot object). We don't
      // know anything about the instance variables, and we can't access them.
      // We need to create one here if we want to use it. Comment out the
      // initialization of bob and see.
      Robot bob = new Robot();
      bob.moveDown();
      System.out.println("location:" + bob.getLocation());
   }
}

We have been using a static variable in Robot since the beginning, but let’s look at how we create our location and MODEL_NUMBER variables in Robot.

private int location;
public static final String MODEL_NUMBER = "XRT354";

The MODEL_NUMBER is static, and the modifier “static” is the only thing that we need to preface our variable with. Here, it is what we call a constant, and generally you will see that they are marked as public, meaning they can been seen by anyone, static, so they are a class variable, and final so they can not be changed once initialized.

What does static really do to a variable?

It binds the variable to the class. It is now initialized the first time the class is accessed, and a local instance of the variable IS NOT created for each new Object created. In practical terms, this means that the variable is shared across all the instances. We’ll get to that in a minute.

How about static methods?

They are also bound to the class, and not an instance of an Object. You will often see utility methods created as static methods. They don’t depend on a particular instance of an object to do any work, and you don’t need an instance of them to use them. I think it is time for examples.

Accessing static variables and methods

public class RobotTesta {

   public static void main(String[] args) {

      Robot bob = new Robot();
      Robot doug = new Robot();

      // both bob and doug know the model number
      // it is the same for both, and can't be changed
      System.out.println("bob:" + bob.MODEL_NUMBER);
      System.out.println("doug:" + doug.MODEL_NUMBER);

      // the prefered way to access it is by using the class name, as it
      // doesn't really belong to bob or doug like an instance variable does
      System.out.println("robot:" + Robot.MODEL_NUMBER);

      // both bob and doug have the method on them to get the model number
      System.out.println("bob:" + bob.getModelNumber());
      System.out.println("doug:" + doug.getModelNumber());

      // the prefered way to access this method is by using the class name, as
      // it doesn't really belong to bob or doug, but the class
      System.out.println("robot:" + Robot.getModelNumber());

      // How can we prove that we don't need bob or doug to access the static
      // variables or methods?
      bob = null;
      doug = null;

      System.out.println("robot:" + Robot.MODEL_NUMBER);
      System.out.println("robot:" + Robot.getModelNumber());
   }
}

Let’s look at an example using just that model number using RobotTesta. Because they are real variables, you can create an object and then access them from the instance like this:

Robot bob = new Robot();
Robot doug = new Robot();
System.out.println("bob:" + bob.MODEL_NUMBER);
System.out.println("doug:" + doug.MODEL_NUMBER);

If you are looking at this code in eclipse you will see a yellow warning arrow on the left side. It says “The static field Robot.MODEL_NUMBER should be accessed in a static way”. What does this mean? Well, remember it is not an instance variable, it is a static variable, so Java would prefer we accessed it that way, like this:

System.out.println("robot:" + Robot.MODEL_NUMBER);

The same helpful warning will show up if you access a static method using an instance:

System.out.println("bob:" + bob.getModelNumber());
System.out.println("doug:" + doug.getModelNumber());

Once again, we should access the class this way :

System.out.println("robot:" + Robot.getModelNumber());

Revisiting static void main

We have been using separate “test” classes to access our various Robot’s, but it wasn’t necessary. I choose to keep the “real” classes separate from the code we would use to observe the behaviors. But we could have just added a static method to the bottom. Look at the bottom of the Robot class in the staticstuff package. At the bottom there is a static main method. We can “run” this Robot class because of it.

public static void main(String[] args) {
   Robot bob = new Robot();
   bob.moveDown();
   System.out.println("location:" + bob.getLocation());
}

One thing that always looks weird when you start looking at this is that you need to create a Robot class inside main. That is because as a static method it does not belong to an instance of Robot, and has no instance to act on. There is no bob or doug to call moveDown() or getLocation() on until we create one.

Dissecting the static void main method signature

When I first started, I thought that the ability to run a Java program was a bit of magic, and I dutifully memorized the public static void main(String[] args) method signature that would magically make my programs run. I would like to show you that it is not so magic after all. In fact, we know all the pieces already. Look at RobotTestb

public class RobotTestb {
   public static void main(String[] args) {
      System.out.println("# of parms:" + args.length);
      for (int i = 0; i < args.length; i++) {
         System.out.println("args[" + i + "]:" + args[i]);
      }
      // this will cause the Java Machine to end immediately
      // System.exit(7);
   }
}

It consists of one method. The magic main method. The only magic that exists is that Java has decided that the method name to look for when running a program via the “java” command, is called main. The rest we will look at now, and really do make sense.

First of all, it is public. Could it be private? That would defeat the purpose. You want someone outside of your class to access your method. It has to be public.

The method is static. Does it have to be? If this is the code that is to kick off, create, or setup your programs, it really has to be static. We don’t have a way to create an instance of the object first, so it has to be static.

How about the void? Do we need that? Java has decided that the main method will not return a value. If they had gone the other way, then we would have had to put a lot of “return null” statements at the end of our main methods when we didn’t have anything to return. Most times there is no reason to return something. If you do need to return some kind of code, like an error code from a java program called from the command line, you can put this into the end of you code :

System.exit(7);

Be careful about this. This kills the virtual machine, so it should only be used in situations where you have to return a code to a shell script.

How about main? Well, you could create any number of static methods in your class, but if you want to “run” your class using the “java” command, either from the command line, or from within eclipse, you have to name a method main.

What is the String[] args part about? Well, the args part could be any valid parameter name you would like. It is short for arguments, but you could use “whatchamacallits” if you would like. The String[] part in front is to indicate that the method could take in an array of Strings. These arguments are often used to pass in parameters to initialize your program. If you call your program without arguments, args will be an empty array, but if you call with a list of Strings separated by spaces, they will show up in the array.

So that’s not so bad, and not too much magic.

How do you call a Java program?

I usually use Eclipse, and if there is a main method, I just right click the source code and choose “Run As…Java Application”. Simple. What if we want to pass arguments? Let’s look at command line and Eclipse ways of doing that.

First, with Eclipse:

Right click the source, and pick “Run As”/”Open Run Dialog..”. If you have already run this program, it has created what Eclipse calls a launch configuration. If you haven’t, you can create one with the “new” icon at the far left. Then click on the “(x)=Arguments” tab. In the first box type a few words. Each of these words will become a parameter passed to our program. Press “Apply”, then “Run”. Look at the output produced. You should see your words.

Now the “real” way:

Bring up a command line, and navigate to the folder that contains the beginning of this package structure. You will have to navigate all the way into the workspace, then find where the package for this class starts. If the package is “net.cyberward.tutorial.oo.staticstuff.test” then you will need to be in the folder that contains the “net” folder.

Now type: javac net\cyberward\tutorial\oo\staticstuff\test\RobotTestb.java This will compile the java program for you. (Where did the “.class” file go?) Now type java net.cyberward.tutorial.oo.staticstuff.test.RobotTestb chris ward You should get output like this:

# of parms:2
args[0]:chris
args[1]:ward

Do we understand System.out.println?

We have been using the line System.out.println(“some text”); in all our examples. Maybe we should take another look at it. It no longer needs to be the magical statement that puts text on the screen.

public class RobotTestd {

   public static void main(String[] args) {

      // use the System object to get the time
      long aTime = System.currentTimeMillis();

      // use different overloaded print methods on out
      System.out.print("Time:"); // print a String
      System.out.print(aTime); // print a long

      // use different overloaded println methods on out
      System.out.println(); // print a 'new line'
      String aVersion = System.getProperty("java.version");
      System.out.println(aVersion);
   }
}

RobotTestd is an example that shows us several System calls. What is System? It is a utility class that provides us access to some of the system resources. You can look up the java docs for this on suns site :

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/System.html

What is the out part? Is that a method? Nope, it is a publicly accessible class variable, just like our MODEL_NUMBER. This variable is not a String, it is a PrintStream. This Printstream is created for us by the VM to allow us to send text to an output device. Printstream has methods on it, like println(), and print(String), and println(String). These methods are not static. Look them up via the api link from above. How do we access them statically? We aren’t. We are accessing System’s PrintStream statically, but “out” is a PrintStream instance the VM created. Therefore, we can call the public methods on that instance.

System.out.println("Robot created.");

So… we use the utility class System, to statically access an instance of PrintStream called “out”, created for us by the VM, calling an instance method “println(String x)” to put the text “Robot created” on the console.

Revisiting static variables

public class Robot5 extends Robot {

   // member variable to hold a particular Robot3's Id
   // do I need to initialize this to zero?
   private int robotId = 0;

   // a static class variable to keep track of the number of Robot3's created
   private static int NUMBER_OF_ROBOTS_CREATED = 0;

   public Robot5() {
      // first let's tell Robot to initialize
      super();
      // now lets give this Robot3 an Id
      robotId = 100 + NUMBER_OF_ROBOTS_CREATED;
      NUMBER_OF_ROBOTS_CREATED++;
      // same as NUMBER_OF_ROBOTS_CREATED = NUMBER_OF_ROBOTS_CREATED + 1;
      // in fact, we could have used :
      // robotId = 100 + NUMBER_OF_ROBOTS_CREATED++;
   }

   /**
    * Return the robot Id of an instance of Robot3
    *
    * @return
    */
   public int getRobotId() {
      return robotId;
   }

   /**
    * Return the number of Robot3's this class has had instantiated
    *
    * @return
    */
   public static int getNumberOfRobotsCreated() {
      return NUMBER_OF_ROBOTS_CREATED;
   }
}
public class RobotTeste {

   public static void main(String[] args) {

      Robot5 bob = new Robot5();
      Robot5 doug = new Robot5();
      Robot5 fred = new Robot5();

      System.out.println("# of robots:" + Robot5.getNumberOfRobotsCreated());
      System.out.println("bob's id:" + bob.getRobotId());
      System.out.println("doug's id:" + doug.getRobotId());
      System.out.println("fred's id:" + fred.getRobotId());

      bob.moveDown();
      doug.moveUp();

      System.out.println("bob's location:" + bob.getLocation());
      System.out.println("doug's location:" + doug.getLocation());
      System.out.println("fred's location:" + fred.getLocation());
   }
}

Let’s make sure we understand the difference between instance and static variables. We are now going to use Robot5. This version of Robot has a static variable and some support code in it to keep track of the number of Robot5s that have been created. RobotTeste is a little test class to show how this works. It creates 3 different Robot5 Objects. Take a look at the output, then at the source code to make sure you understand how the interactions work between the instances and the static variable.

public class RobotTestf {

   public static void main(String[] args) {

      // Let's start by creating 3 Robot3's
      Robot5 bob = new Robot5();
      Robot5 doug = new Robot5();
      Robot5 fred = new Robot5();

      // How many Robots have been created at this point?
      // How many Robot3 have been created at this point?
      System.out.println("# of robot5s:" + Robot5.getNumberOfRobotsCreated());
      System.out.println("bob's id:" + bob.getRobotId());
      System.out.println("doug's id:" + doug.getRobotId());
      System.out.println("fred's id:" + fred.getRobotId());

      Robot miniBob = new Robot();
      // How many Robots have been created at this point?
      // How many Robot5's have been created at this point?
      System.out.println("# of robot5s:" + Robot5.getNumberOfRobotsCreated());
      // Why does miniBob not have an Id?
      // System.out.println(miniBob.getRobotId());

      Robot miniDoug = new Robot5();
      // How many Robots have been created at this point?
      // How many Robot5's have been created at this point?
      System.out.println("# of robot5s:" + Robot5.getNumberOfRobotsCreated());
      // Why does miniDoug not have an Id?
      // System.out.println(miniDoug.getRobotId());
   }
}

RobotTestf goes one step further. It adds Robot back into the mix. We create Robot5’s and Robots. Again, look at the output, and the number of Robots that get created when. Remember, Robot5 extends Robot, but that doesn’t put Robot5’s functionality on Robot. Robot5 inherits the functionality from Robot.

[drain file 4 show tableRow]

[drain file 5 show tableRow]

Type Download Name Version Size Updated Hits
Series NavigationIntro to Java Objects and ClassesIntro To Java Classes Revisited