Tuesday, January 25, 2011

Chapter 13: Statics

Static is one of the most important and powerful keywords in the java programming language. It can alter the behavior of variables and methods. The purpose of this chapter is to take a detailed look at this feature.

Static Variables and Methods

The static modifier has such a profound impact on the behavior of a method or variable that we’re treating it as a concept entirely separate from the other modifiers. To understand the way a static member works, we’ll look first at a reason for using one. Imagine you’ve got a utility class with a method that always runs the same way; its sole function is to return, say, a random number. It wouldn’t matter which instance of the class performed the method—it would always behave exactly the same way. In other words, the method’s behavior has no dependency on the state (instance variable values) of an object. So why, then, do you need an object when the method will never be instance-specific? Why not just ask the class itself to run the method?

Let’s imagine another scenario: Suppose you want to keep a running count of all instances instantiated from a particular class. Where do you actually keep that variable? It won’t work to keep it as an instance variable within the class whose instances you’re tracking, because the count will just be initialized back to a default value with each new instance. The answer to both the utility-method-always-runs-the-same scenario and the keep-a-running-total-of-instances scenario is to use the static modifier. Variables and methods marked static belong to the class, rather than to any particular instance. In fact, you can use a static method or variable without having any instances of that class at all. You need only have the class available to be able to invoke a static method or access a static variable. static variables, too, can be accessed without having an instance of a class. But if there are instances, a static variable of a class will be shared by all instances of that class; there is only one copy.

The following code declares and uses a static counter variable:

class Car {
static int CarCount = 0; // Declare and initialize
// static variable
public Car() {
CarCount += 1; // Modify the value in the constructor
}
public static void main (String [] args) {
new Car();
new Car();
new Car();
System.out.println("Car count is now " + CarCount);
}
}

In the preceding code, the static CarCount variable is set to zero when the Car class is first loaded by the JVM, before any Car instances are created! (By the way, you don’t actually need to initialize a static variable to zero; static variables get the same default values instance variables get.) Whenever a Car instance is created, the Car constructor runs and increments the static CarCount variable. When this code executes, three Car instances are created in main(), and the result is

Car count is now 3

Now imagine what would happen if CarCount were an instance variable (in other words, nonstatic):
class Car {
int CarCount = 0; // Declare and initialize
// instance variable
public Car() {
CarCount += 1; // Modify the value in the constructor
}
public static void main (String [] args) {
new Car();
new Car();
new Car();
System.out.println("Car count is now " + CarCount);
}
}

When this code executes, it should still create three Car instances in main(), but the result is...a compiler error! We can’t get this code to compile, let alone run.
Car.java:11: nonstatic variable CarCount cannot be referenced

from a static context
System.out.println("Car count is " + CarCount);
^
1 error

The JVM doesn’t know which Car object’s CarCount you’re trying to access. The problem is that main() is itself a static method, and thus isn’t running against any particular instance of the class, rather just on the class itself. A static method can’t access a nonstatic (instance) variable, because there is no instance! That’s not to say there aren’t instances of the class alive on the heap, but rather that even if there are, the static method doesn’t know anything about them. The same applies to instance methods; a static method can’t directly invoke a nonstatic method. Think static = class, nonstatic = instance. Making the method called by the JVM (main()) a static method means the JVM doesn’t have to create an instance of your class just to start running code.

Exam Tip:
One of the mistakes most often made by new Java programmers is attempting to access an instance variable (which means nonstatic variable) from the static main() method (which doesn’t know anything about any instances, so it can’t access the variable). The following code is an example of illegal access of a nonstatic variable from a static method:
class Bad {
int x = 3;
public static void main (String [] args) {
System.out.println("x is " + x);
}
}
Understand that this code will never compile, because you can’t access a nonstatic (instance) variable from a static method. Just think of the compiler saying, “Hey, I have no idea which Bad object’s x variable you’re trying to print!” Remember, it’s the class running the main() method, not an instance of the class.

Of course, the tricky part for the exam is that the question won’t look as obvious as the preceding code. The problem you’re being tested for—accessing a nonstatic variable from a static method—will be buried in code that might appear to be testing something else. For example, the preceding code would be more likely to appear as
class Bad {
int x = 3;
float y = 4.3f;
public static void main (String [] args) {
for (int z = x; z < ++x; z--, y = y + z) // complicated looping and branching code } } So while you’re trying to follow the logic, the real issue is that x and y can’t be used within main(), because x and y are instance, not static, variables! The same applies for accessing nonstatic methods from a static method. The rule is, a static method of a class can’t access a nonstatic (instance) method or variable of its own class.





Accessing Static Methods and Variables

Since you don’t need to have an instance in order to invoke a static method or access a static variable, then how do you invoke or use a static member? What’s the syntax? We know that with a regular old instance method, you use the dot operator on a reference to an instance:

class Car {
int CarSize = 0;
public int getCarSize() {
return CarSize;
}
public Car(int s) {
CarSize = s;
}
public static void main (String [] args) {
Car f = new Car(25);
System.out.println(f.getCarSize()); // Access instance
// method using f
}
}

In the preceding code, we instantiate a Car, assign it to the reference variable f, and then use that f reference to invoke a method on the Car instance we just created. In other words, the getCarSize() method is being invoked on a specific Car object on the heap.

But this approach (using a reference to an object) isn’t appropriate for accessing a static method, because there might not be any instances of the class at all! So, the way we access a static method (or static variable) is to use the dot operator on the class name, as opposed to using it on a reference to an instance, as follows:

class Car {
static int CarCount = 0; // Declare and initialize
// static variable
public Car() {
CarCount += 1; // Modify the value in the constructor
}
}

class TestCar {
public static void main (String [] args) {
new Car();
new Car();
new Car();
System.out.print("CarCount:"+Car.CarCount); //Access
// static variable
}
}

But just to make it really confusing, the Java language also allows you to use an object reference variable to access a static member:
Car f = new Car();
int Cars = f.CarCount; // Access static variable
// CarCount using f

In the preceding code, we instantiate a Car, assign the new Car object to the reference variable f, and then use the f reference to invoke a static method! But even though we are using a specific Car instance to access the static method, the rules haven’t changed. This is merely a syntax trick to let you use an object reference variable (but not the object it refers to) to get to a static method or variable, but the static member is still unaware of the particular instance used to invoke the static member. In the Car example, the compiler knows that the reference variable f is of type Car, and so the Car class static method is run with no awareness or concern for the Car instance at the other end of the f reference. In other words, the compiler cares only that reference variable f is declared as type Car.

Finally, remember that static methods can’t be overridden! This doesn’t mean they can’t be redefined in a subclass, but redefining and overriding isn’t the same thing. Let’s take a look at an example of a redefined (remember, not overridden), static method:

class Car {
static void drive() {
System.out.print("a ");
}
}
class Ferrari extends Car {
static void drive() { // it's a redefinition & not an override
System.out.print("d ");
}
public static void main(String [] args) {
Car [] a = {new Car(), new Ferrari(), new Car()};
for(int x = 0; x < a.length; x++) a[x].drive(); // invoke the static method } } Running this code produces the output: a a a Remember, the syntax a[x].drive() is just a shortcut (the syntax trick)...the compiler is going to substitute something like Car.drive() instead. This happens because the Array is of type Car and so the static method inside the Car class is used even though there is an instance of Ferrari in the list. Previous Chapter: Chapter 12 - Constructors and Instantiation

Next Chapter: Chapter 13 - Coupling & Cohesion

4 comments:

  1. why is this redefinition in the last example?

    ReplyDelete
  2. @ Michee

    What redefinition are you talking about? Am not able to understand the question here. Sorry.

    Anand

    ReplyDelete
  3. " Let’s take a look at an example of a redefined (remember, not overridden), static method:

    class Car {
    static void drive() {
    System.out.print("a ");
    }
    }
    class Ferrari extends Car {
    static void drive() { // it's a redefinition & not an override
    System.out.print("d ");
    }
    "

    ReplyDelete
  4. @ Michee

    The Redefinition is because we are trying to explain the concept that is similar to overriding but isnt actually overriding.

    ReplyDelete

© 2013 by www.inheritingjava.blogspot.com. All rights reserved. No part of this blog or its contents may be reproduced or transmitted in any form or by any means, electronic, mechanical, photocopying, recording, or otherwise, without prior written permission of the Author.

ShareThis

Google+ Followers

Followers