static is one of the optional java specifiers applicable to variable, method and inner class (OCA don't test inner class).
When a variable or method is marked as static, they can be directly accessed via class name or a class type reference variable.
non-static variable and method cannot be referenced from a static context (static method, static initializer).
static variable and method can be referenced from a non-static context (non-static method, instance initializer).
static variable is per class, all the class instance share the same copy of static variable.
instance variable (non-static variable) is per instance, each class instance have its own copy of instance variable.
{statements} block is the instance initializer, statements are executed when a class instance is created with new keyword.
static{statements} block is the static initializer, statements are executed when a class is used the first time.
OCAJP>cat test.java
//static class test{ //error: modifier static not allowed here
class test{
public static void main(String... args) {
testBench.main(new String[0]);
}
static int onlyOne = 0; //static variable
int eachOne = 0; //instance variable
static int getOnlyOne() { //static method
//eachOne ++; //error: non-static variable eachOne cannot be referenced from a static context
//getEachOne(); //error: non-static method getEachOne() cannot be referenced from a static context
return onlyOne ++;
}
int getEachOne() { //instance method
onlyOne ++; //no problem
getOnlyOne(); //no problem
return eachOne ++;
}
static{ //static initializer
onlyOne ++;
getOnlyOne();
//eachOne ++; //error: non-static variable eachOne cannot be referenced from a static context
//getEachOne(); //error: non-static method getEachOne() cannot be referenced from a static context
}
{ //instance initializer
onlyOne ++;
getOnlyOne();
eachOne ++;
getEachOne(); //increase onlyOne by 2
}
}
class testBench{
public static void main(String... args){ //main is also a static method
System.out.print(" "+test.getOnlyOne()); //2
System.out.print(" "+test.onlyOne); //3
//System.out.print(" "+test.eachOne); //error: non-static variable eachOne cannot be referenced from a static context
//System.out.print(" "+test.getEachOne()); //error: non-static method getEachOne() cannot be referenced from a static context
System.out.print(" "+new test().getEachOne()); //2
System.out.print(" "+new test().eachOne); //2
System.out.print(" "+new test().getOnlyOne()); //no problem //17
System.out.print(" "+new test().onlyOne); //no problem //22
System.out.print(" "+test.getOnlyOne()); //22
System.out.print(" "+test.onlyOne); //23
//method(); //error: non-static variable eachOne cannot be referenced from a static context
test nullref = null; //no problem, nullref still have type test, which is enough to call static variable and methods
System.out.print(" " + nullref.getOnlyOne()); //23
System.out.print(" " + nullref.onlyOne); //24
//test ref;
//System.out.print(" " + ref.onlyOne); //error: variable ref might not have been initialized
new testBench().method();
}
void method() {
System.out.print(" "+test.getOnlyOne()); //no problem //24
System.out.print(" "+test.onlyOne); //no problem //25
//System.out.print(" "+test.eachOne); //error: non-static variable eachOne cannot be referenced from a static context
System.out.print(" "+new test().getEachOne());//2
System.out.print(" "+new test().eachOne); //2
System.out.println();
}
}
OCAJP>javac test.java
OCAJP>java test
2 3 2 2 17 22 22 23 23 24 24 25 2 2
As the above example shows, instance variable is per instance. The following statements are executed twice in the code, each time we got 2 and 2: when new test() is executed, eachOne's value starts with 0, instance initializer increase eachOne's value to 2, then getEachOne() returns eachOne ++, the returned value is 2, after value return, eachOne's value became 3. In the next statement, when new test() is executed, eachOne's value start from 0 again, increase to 2 in instance initializer.
System.out.print(" "+new test().getEachOne()); //2
System.out.print(" "+new test().eachOne); //2
On the other hand, static variable is per class, its value starts from 0 and keeps increasing afterwards. (If tracing code is too hard, just copy the file to eclipse or intellij IDE and run debugger to figure it out. Put break point at the first line of every method and initializer block.)
When the following statements are executed, since test is used the first time, static initializer increase onlyOne's value to 2, then getOnlyOne() increase onlyOne's value to 3.
When the following statements are executed, since test is used the first time, static initializer increase onlyOne's value to 2, then getOnlyOne() increase onlyOne's value to 3.
System.out.print(" "+test.getOnlyOne()); //2
System.out.print(" "+test.onlyOne); //3
onlyOne == 3
After that,
onlyOne == 7
then getEachOne() increase onlyOne's value by 2 in method body.
onlyOne == 9
System.out.print(" "+new test().eachOne); //2
call of new test() increase onlyOne's value by 4 in instance initializer
onlyOne == 13
System.out.print(" "+test.getOnlyOne()); //22
getOnlyOne() returns 22, increase onlyOne's value to 23
onlyOne == 23
System.out.print(" "+test.onlyOne); //23
onlyOne == 23
...
The last OCA topic about static is static imports. We already know how to import a class or all the classes in a package. static imports is used to import static class members.
System.out.print(" "+new test().getEachOne()); //2
call of new test() increase onlyOne's value by 4 in instance initializer, onlyOne == 7
then getEachOne() increase onlyOne's value by 2 in method body.
onlyOne == 9
System.out.print(" "+new test().eachOne); //2
call of new test() increase onlyOne's value by 4 in instance initializer
onlyOne == 13
System.out.print(" "+new test().getOnlyOne()); //no problem //17
new test() increase onlyOne's value by 4 in instance initializer
onlyOne == 17
getOnlyOne() returns 17, increase onlyOne's value to 18
onlyOne == 18
System.out.print(" "+new test().onlyOne); //no problem //22
new test() increase onlyOne's value by 4 in instance initializer
onlyOne == 22
onlyOne == 17
getOnlyOne() returns 17, increase onlyOne's value to 18
onlyOne == 18
System.out.print(" "+new test().onlyOne); //no problem //22
new test() increase onlyOne's value by 4 in instance initializer
onlyOne == 22
System.out.print(" "+test.getOnlyOne()); //22
getOnlyOne() returns 22, increase onlyOne's value to 23
System.out.print(" "+test.onlyOne); //23
onlyOne == 23
...
The last OCA topic about static is static imports. We already know how to import a class or all the classes in a package. static imports is used to import static class members.
OCAJP>cat home/Home.java hotel/Passenger.java
package home;
public class Home{
public static String msg = "don't disturb";
public static void rest() {}
public static void eat() {}
public void play() {}
}
package hotel;
import static home.Home.rest;
//import static home.Home.play; //error: cannot find symbol
//import home.Home.eat; //error: cannot find symbol
//import static home.Home; //error: static import only from classes and interfaces
import static home.Home.eat;
class Passenger{
public static void main(String[] args) {
rest();
//play(); //error: cannot find symbol
//missing import home.*;
//Home.rest(); //error: cannot find symbol
home.Home.rest();
//home.new Home().play(); //error: cannot find symbol
eat();
}
}
OCAJP>javac home/Home.java hotel/Passenger.java
OCAJP>java hotel/Passenger
Back OCAJP