问题
My question is about one particular usage of static keyword. It is possible to use static
keyword to cover a code block within a class which does not belong to any function. For example following code compiles:
public class Test {
private static final int a;
static {
a = 5;
doSomething(a);
}
private static int doSomething(int x) {
return (x+5);
}
}
If you remove the static
keyword it complains because the variable a
is final
. However it is possible to remove both final
and static
keywords and make it compile.
It is confusing for me in both ways. How am I supposed to have a code section that does not belong to any method? How is it possible to invoke it? In general, what is the purpose of this usage? Or better, where can I find documentation about this?
回答1:
The code block with the static modifier signifies a class initializer; without the static modifier the code block is an instance initializer.
Class initializers are executed in the order they are defined (top down, just like simple variable initializers) when the class is loaded (actually, when it's resolved, but that's a technicality).
Instance initializers are executed in the order defined when the class is instantiated, immediately before the constructor code is executed, immediately after the invocation of the super constructor.
If you remove static
from int a
, it becomes an instance variable, which you are not able to access from the static initializer block. This will fail to compile with the error "non-static variable a cannot be referenced from a static context".
If you also remove static
from the initializer block, it then becomes an instance initializer and so int a
is initialized at construction.
回答2:
Uff! what is static initializer?
The static initializer is a static {}
block of code inside java class, and run only one time before the constructor or main method is called.
OK! Tell me more...
- is a block of code
static { ... }
inside any java class. and executed by virtual machine when class is called. - No
return
statements are supported. - No arguments are supported.
- No
this
orsuper
are supported.
Hmm where can I use it?
Can be used anywhere you feel ok :) that simple. But I see most of the time it is used when doing database connection, API init, Logging and etc.
Don't just bark! where is example?
package com.example.learnjava;
import java.util.ArrayList;
public class Fruit {
static {
System.out.println("Inside Static Initializer.");
// fruits array
ArrayList<String> fruits = new ArrayList<>();
fruits.add("Apple");
fruits.add("Orange");
fruits.add("Pear");
// print fruits
for (String fruit : fruits) {
System.out.println(fruit);
}
System.out.println("End Static Initializer.\n");
}
public static void main(String[] args) {
System.out.println("Inside Main Method.");
}
}
Output???
Inside Static Initializer.
Apple
Orange
Pear
End Static Initializer.
Inside Main Method.
Hope this helps!
回答3:
The static
block is a "static initializer".
It's automatically invoked when the class is loaded, and there's no other way to invoke it (not even via Reflection).
I've personally only ever used it when writing JNI code:
class JNIGlue {
static {
System.loadLibrary("foo");
}
}
回答4:
This is directly from http://www.programcreek.com/2011/10/java-class-instance-initializers/
1. Execution Order
Look at the following class, do you know which one gets executed first?
public class Foo {
//instance variable initializer
String s = "abc";
//constructor
public Foo() {
System.out.println("constructor called");
}
//static initializer
static {
System.out.println("static initializer called");
}
//instance initializer
{
System.out.println("instance initializer called");
}
public static void main(String[] args) {
new Foo();
new Foo();
}
}
Output:
static initializer called
instance initializer called
constructor called
instance initializer called
constructor called
2. How do Java instance initializer work?
The instance initializer above contains a println statement. To understand how it works, we can treat it as a variable assignment statement, e.g., b = 0
. This can make it more obvious to understand.
Instead of
int b = 0
, you could write
int b;
b = 0;
Therefore, instance initializers and instance variable initializers are pretty much the same.
3. When are instance initializers useful?
The use of instance initializers are rare, but still it can be a useful alternative to instance variable initializers if:
- Initializer code must handle exceptions
- Perform calculations that can’t be expressed with an instance variable initializer.
Of course, such code could be written in constructors. But if a class had multiple constructors, you would have to repeat the code in each constructor.
With an instance initializer, you can just write the code once, and it will be executed no matter what constructor is used to create the object. (I guess this is just a concept, and it is not used often.)
Another case in which instance initializers are useful is anonymous inner classes, which can’t declare any constructors at all. (Will this be a good place to place a logging function?)
Thanks to Derhein.
Also note that Anonymous classes that implement interfaces [1] have no constructors. Therefore instance initializers are needed to execute any kinds of expressions at construction time.
回答5:
"final" guarantees that a variable must be initialized before end of object initializer code. Likewise "static final" guarantees that a variable will be initialized by the end of class initialization code. Omitting the "static" from your initialization code turns it into object initialization code; thus your variable no longer satisfies its guarantees.
回答6:
You will not write code into a static block that needs to be invoked anywhere in your program. If the purpose of the code is to be invoked then you must place it in a method.
You can write static initializer blocks to initialize static variables when the class is loaded but this code can be more complex..
A static initializer block looks like a method with no name, no arguments, and no return type. Since you never call it it doesn't need a name. The only time its called is when the virtual machine loads the class.
回答7:
when a developer use an initializer block, the Java Compiler copies the initializer into each constructor of the current class.
Example:
the following code:
class MyClass {
private int myField = 3;
{
myField = myField + 2;
//myField is worth 5 for all instance
}
public MyClass() {
myField = myField * 4;
//myField is worth 20 for all instance initialized with this construtor
}
public MyClass(int _myParam) {
if (_myParam > 0) {
myField = myField * 4;
//myField is worth 20 for all instance initialized with this construtor
//if _myParam is greater than 0
} else {
myField = myField + 5;
//myField is worth 10 for all instance initialized with this construtor
//if _myParam is lower than 0 or if _myParam is worth 0
}
}
public void setMyField(int _myField) {
myField = _myField;
}
public int getMyField() {
return myField;
}
}
public class MainClass{
public static void main(String[] args) {
MyClass myFirstInstance_ = new MyClass();
System.out.println(myFirstInstance_.getMyField());//20
MyClass mySecondInstance_ = new MyClass(1);
System.out.println(mySecondInstance_.getMyField());//20
MyClass myThirdInstance_ = new MyClass(-1);
System.out.println(myThirdInstance_.getMyField());//10
}
}
is equivalent to:
class MyClass {
private int myField = 3;
public MyClass() {
myField = myField + 2;
myField = myField * 4;
//myField is worth 20 for all instance initialized with this construtor
}
public MyClass(int _myParam) {
myField = myField + 2;
if (_myParam > 0) {
myField = myField * 4;
//myField is worth 20 for all instance initialized with this construtor
//if _myParam is greater than 0
} else {
myField = myField + 5;
//myField is worth 10 for all instance initialized with this construtor
//if _myParam is lower than 0 or if _myParam is worth 0
}
}
public void setMyField(int _myField) {
myField = _myField;
}
public int getMyField() {
return myField;
}
}
public class MainClass{
public static void main(String[] args) {
MyClass myFirstInstance_ = new MyClass();
System.out.println(myFirstInstance_.getMyField());//20
MyClass mySecondInstance_ = new MyClass(1);
System.out.println(mySecondInstance_.getMyField());//20
MyClass myThirdInstance_ = new MyClass(-1);
System.out.println(myThirdInstance_.getMyField());//10
}
}
I hope my example is understood by developers.
回答8:
The static code block can be used to instantiate or initialize class variables (as opposed to object variables). So declaring "a" static means that is only one shared by all Test objects, and the static code block initializes "a" only once, when the Test class is first loaded, no matter how many Test objects are created.
来源:https://stackoverflow.com/questions/335311/what-is-the-difference-between-a-static-and-a-non-static-initialization-code-blo