Thursday 9 March 2017

Understanding static, Introducing final & Arrays Revisited - Java Tutorials

Understanding static


There will be times when you will want to define a class member that will be used independently of any object of that class. Normally a class member must be accessed only in conjunction with an object of its class. However, it is possible to create a member that can be used by itself, without reference to a specific instance. To create such a member, precede its declaration with the keyword static. When a member is declared static, it can be accessed before any objects of its class are created, and without reference to any object. You can declare both methods and variables to be static. The most common example of a static member is main( ). main( ) is declared as static because it must be called before any objects exist.

Instance variables declared as static are, essentially, global variables. When objects of its class are declared, no copy of a static variable is made. Instead, all instances of the class share the same static variable.

Methods declared as static have several restrictions:
  • They can only call other static methods.
  • They must only access static data.
  • They cannot refer to this or super in any way. (The keyword super relates to inheritance and is described in the next chapter.)

If you need to do computation in order to initialize your static variables, you can declare a static block which gets executed exactly once, when the class is first loaded. The following example shows a class that has a static method, some static variables, and a static initialization block:

  // Demonstrate static variables, methods, and blocks.
  class UseStatic {
    static int a = 3;
    static int b;

    static void meth(int x) {
      System.out.println("x = " + x);
      System.out.println("a = " + a);
      System.out.println("b = " + b);
    }

    static {
      System.out.println("Static block initialized.");
      b = a * 4;
    }

    public static void main(String args[]) {
      meth(42);
    }
  }

As soon as the UseStatic class is loaded, all of the static statements are run. First, a is set to 3, then the static block executes (printing a message), and finally, b is initialized to a * 4 or 12. Then main( ) is called, which calls meth( ), passing 42 to x. The three println( ) statements refer to the two static variables a and b, as well as to the local variable x.

It is illegal to refer to any instance variables inside of a static method.

Here is the output of the program:

  Static block initialized.
  x = 42
  a = 3
  b = 12

Outside of the class in which they are defined, static methods and variables can be used independently of any object. To do so, you need only specify the name of their class followed by the dot operator. For example, if you wish to call a static method from outside its class, you can do so using the following general form:

  classname.method( )

Here, classname is the name of the class in which the static method is declared. As you can see, this format is similar to that used to call non-static methods through object- reference variables. A static variable can be accessed in the same way—by use of the dot operator on the name of the class. This is how Java implements a controlled version of global methods and global variables.

Here is an example. Inside main( ), the static method callme( ) and the static variable b are accessed outside of their class.

  class StaticDemo {
    static int a = 42;
    static int b = 99;
    static void callme() {
      System.out.println("a = " + a);
    }
  }

  class StaticByName {
    public static void main(String args[]) {
      StaticDemo.callme();
      System.out.println("b = " + StaticDemo.b);
    }
  }

Here is the output of this program:

  a = 42
  b = 99




Introducing final

A variable can be declared as final. Doing so prevents its contents from being modified. This means that you must initialize a final variable when it is declared. (In this usage, final is similar to const in C/C++/C#.) For example:

  final int FILE_NEW = 1;
  final int FILE_OPEN = 2;
  final int FILE_SAVE = 3;
  final int FILE_SAVEAS = 4;
  final int FILE_QUIT = 5;

Subsequent parts of your program can now use FILE_OPEN, etc., as if they were constants, without fear that a value has been changed.

It is a common coding convention to choose all uppercase identifiers for final variables. Variables declared as final do not occupy memory on a per-instance basis. Thus, a final variable is essentially a constant.

The keyword final can also be applied to methods, but its meaning is substantially different than when it is applied to variables. This second usage of final is described in the next chapter, when inheritance is described.




Arrays Revisited

Arrays were introduced earlier in this book, before classes had been discussed. Now that you know about classes, an important point can be made about arrays: they are implemented as objects. Because of this, there is a special array attribute that you will want to take advantage of. Specifically, the size of an array—that is, the number of elements that an array can hold—is found in its length instance variable. All arrays have this variable, and it will always hold the size of the array. Here is a program that demonstrates this property:

  // This program demonstrates the length array member.
  class Length {
    public static void main(String args[]) {
      int a1[] = new int[10];
      int a2[] = {3, 5, 7, 1, 8, 99, 44, -10};
      int a3[] = {4, 3, 2, 1};

      System.out.println("length of a1 is " + a1.length);
      System.out.println("length of a2 is " + a2.length);
      System.out.println("length of a3 is " + a3.length);
    }
  }

This program displays the following output:

  length of a1 is 10
  length of a2 is 8
  length of a3 is 4

As you can see, the size of each array is displayed. Keep in mind that the value of length has nothing to do with the number of elements that are actually in use. It only reflects the number of elements that the array is designed to hold.

You can put the length member to good use in many situations. For example, here is an improved version of the Stack class. As you might recall, the earlier versions of this class always created a ten-element stack. The following version lets you create stacks of any size. The value of stck.length is used to prevent the stack from overflowing.

  // Improved Stack class that uses the length array member.
  class Stack {
    private int stck[];
    private int tos;

    // allocate and initialize stack
    Stack(int size) {
      stck = new int[size];
      tos = -1;
    }

    // Push an item onto the stack
    void push(int item) {
      if(tos==stck.length-1) // use length member
        System.out.println("Stack is full.");
      else
        stck[++tos] = item;
    }

    // Pop an item from the stack
    int pop() {
      if(tos < 0) {
        System.out.println("Stack underflow.");
        return 0;
      }
      else
        return stck[tos--];
    }
  }

  class TestStack2 {
    public static void main(String args[]) {
      Stack mystack1 = new Stack(5);
      Stack mystack2 = new Stack(8);

      // push some numbers onto the stack
      for(int i=0; i<5; i++) mystack1.push(i);
      for(int i=0; i<8; i++) mystack2.push(i);

      // pop those numbers off the stack
      System.out.println("Stack in mystack1:");
      for(int i=0; i<5; i++)
        System.out.println(mystack1.pop());

      System.out.println("Stack in mystack2:");
      for(int i=0; i<8; i++)
        System.out.println(mystack2.pop());
    }
  }

Notice that the program creates two stacks: one five elements deep and the other eight elements deep. As you can see, the fact that arrays maintain their own length information makes it easy to create stacks of any size.

No comments:

Post a Comment