OCA Java SE 8 Method - Java Static Methods and Fields








Static methods don't require an instance of the class.

They are shared among all users of the class.

Each class has a copy of the instance variables.

public class Main { 
  public static int count = 0;               // static variable 
  public static void main(String[] args) {      // static method 
    System.out.println(count); 
  } 
} 

We said that the JVM basically calls Main.main() to get the program started.

We can have a MainTester that does nothing but call the main() method.

public class MainTester { 
  public static void main(String[] args) { 
    Main.main(new String[0]);          // call static method 
  } 
} 

When we run MainTester, it makes a call to the main() method of Main, which prints the value of count.

It shows that main() can be called just like any other static method.

Static methods are good for utility or helper methods that don't require any object state.

Static fields are good for state that is shared by all instances of a class, like a counter.





Calling a Static Variable or Method

To access a static member, put the classname before the method or variable and you are done. For example:

System.out.println(Main.count); 
Main.main(new String[0]); 

You can use an instance of the object to call a static method. The compiler checks for the type of the reference and uses that instead of the object.

This code is perfectly legal:

public class Main {
  static int count = 0;

  public static void main(String[] argv) {
    Main k = new Main();
    System.out.println(k.count); // k is a Main, line 6
    k = null;
    System.out.println(k.count); // k is still a Main, line 8
  }
}

This code outputs 0 twice. Line 6 sees that k is a Main and count is a static variable, so it reads that static variable.

Line 8 does the same thing. Java doesn't care that k happens to be null.

Since we are looking for a static, it doesn't matter.

One more time because this is really important: what does the following output?

public class Main {
  static int count = 0;

  public static void main(String[] argv) {
 
    Main.count = 4; 
    Main k1 = new Main(); 
    Main k2 = new Main(); 
    k1.count = 6; 
    k2.count = 5; 
    System.out.println(Main.count); 
  }
}

There is only one count variable since it is static. It is set to 4, then 6, and finally winds up as 5.





Static vs. Instance

A static member cannot call an instance member.

The following code is a common mistake to make:

public class Main { 
  private String name = "Static class"; 
  public static void first() {  } 
  public static void second() {  } 
  public void third() {  System.out.println(name); } 
  public static void main(String args[]) { 
    first(); 
    second(); 
    third();          // DOES NOT COMPILE 
  } 
} 

The compiler will error about making a static reference to a nonstatic method.

If we fix this by adding static to third(), we create a new problem. third() is referring to nonstatic name. Adding static to name as well would solve the problem.

Another solution would have been to call third as an instance method-for example, new Static().third();.

A static method or instance method can call a static method since static methods don't require an object to use.

Only an instance method can call another instance method from the same class without using a reference variable, since instance methods do require an object.

Static Variables

In the following code we want the count to increase over time.

Just as with instance variables, you can initialize a static variable on the line it is declared:

public class Initializers { 
  private static int counter = 0;          // initialization 
} 

Other static variables are meant to never change during the program.

This type of variable is known as a constant.

It uses the final modifier to ensure the variable never changes.

static final constants use a different naming convention than other variables.

They use all uppercase letters with underscores between "words."

For example:

public class Initializers { 
  private static final int NUM_BUCKETS = 45; 
  public static void main(String[] args) { 
     NUM_BUCKETS = 5;  // DOES NOT COMPILE 
  } 
} 

The compiler would prevent from accidentally updating a final variable.

Look at the following code.

private static final ArrayList<String> values = new ArrayList<>(); 
public static void main(String[] args) { 
  values.add("changed"); 
} 

It does compile. values is a reference variable. We can call methods on reference variables.

The compiler ensures that we don't try to reassign the final values to point to a different object, like another ArrayList in this case.

Static Initialization

Static Initialization adds the static keyword to specify they should be run when the class is first used.

For example:

private static final int NUM_SECONDS_PER_HOUR; 
static { 
  int numSecondsPerMinute = 60; 
  int numMinutesPerHour = 60; 
  NUM_SECONDS_PER_HOUR = numSecondsPerMinute * numMinutesPerHour; 
} 

The static initializer runs when the class is first used. The statements run and assign any static variables as needed.

The final variables are allowed to be reassigned for the first time in the static initializer.

Let's try another example to make sure you understand the distinction:

1: private static int one; 
2: private static final int two; 
3: private static final int three = 3; 
4: private static final int four;     // DOES NOT COMPILE 
5: static { 
6:   one = 1; 
7:   two = 2; 
8:   three = 3;     // DOES NOT COMPILE 
9:   two = 4;     // DOES NOT COMPILE 
10:} 

Line 1 declares a static variable that is not final. It can be assigned as many times as we like.

Line 2 declares a final variable without initializing it. This means we can initialize it exactly once in a static block.

Line 8 doesn't compile because this is the second attempt.

Line 3 declares a final variable and initializes it at the same time. We are not allowed to assign it again, so line 9 doesn't compile.

Line 4 declares a final variable that never gets initialized. The compiler gives a compiler error because it knows that the static blocks are the only place the variable could possibly get initialized.

Static Imports

Arrays.asList is a static method and we can write the code to use a static import yields the following:

import java.util.List; 
import static java.util.Arrays.asList;          // static import 
public class StaticImports { 
  public static void main(String[] args) { 
    List<String> list = asList("one", "two");     // no Arrays. 
  } 
} 

In this example, we are specifically importing the asList method.

This means that any time we refer to asList in the class, it will call Arrays.asList().

If we created an asList method in our StaticImports class. Java would use the method we coded.

This example shows almost everything you can do wrong.

1: import static java.util.Arrays; // DOES NOT COMPILE 
2: import static java.util.Arrays.asList; 
3: static import java.util.Arrays.*;  // DOES NOT COMPILE 
4: public class Main { 
5:    public static void main(String[] args) { 
6:      Arrays.asList("one");  // DOES NOT COMPILE 
7:   } 
8: } 

Line 1 tries to use a static import to import a class.

static imports are only for importing static members. Regular imports are for importing a class.

Line 3 tries to see if you are paying attention to the order of keywords. The syntax is import static and not vice versa.

For Line 6, we imported the asList method on line 2. However, we did not import the Arrays class anywhere. It okay to write asList("one"); but not Arrays.asList("one");.

The compiler will complain if you try to explicitly do a static import of two methods with the same name or two static variables with the same name. For example:

import static statics.A.TYPE; 
import static statics.B.TYPE;     // DOES NOT COMPILE