通常来说,执行new创建对象时,数据存储空间才被分配,其方法才共外界调用。(非static域和方法必须知道和它们一起运作的特定对象)
但是当声明一个事物是static时,意味着这个域或方法不会与包含它的那个类的任何对象实例关联在一起。
例子:
class StaticTest{
static int i = 47;
}
现在,即使创建两个StaticTest对象,StaticTest.i也只有一份存储空间,这两个对象共享一个i。
StaticTest st1 = new StaticTest();
StaticTest st2 = new StaticTest();
在这里,st1.i和st2.i指向同一存储空间,具有相同的值47
引用static变量有两种方法:
- 通过一个对象去定位它。eg:
st2.i;
通过其类名直接引用(这对于非静态成员是不行的)。 eg:
StaticTest.i++;
使用类名是引用static变量的首选方式,不仅强调了static结构,在某些情况下为编译器进行优化提供更佳的可能。
定义静态方法的方式和定义静态变量类似。static方法的重要用法就是在不创建任何对象的前提下就能调用它,这一点对于定义main()方法很重要,这个方法是运行一个应用的入口点。
静态数据的初始化
- 列表内容无论创建多少个对象,静态数据都只占用一份存储区域。
- 如果一个域是静态的基本类型域,且没有对它进行初始化,那么它就会获得基本类型的标准初值;如果它是一个对象引用,则默认初始化值是null。
/**
* 类的初始化顺序 1. 静态变量 2. 定义初始化 3. 构造函数
* 一个例子如下:
*/
class Bowl {
Bowl(int marker) {
System.out.println("Bowl(" + marker + ")");
}
void f1(int marker) {
System.out.println("f1(" + marker + ")");
}
}
class Table {
static Bowl bowl1 = new Bowl(1);
Table() {
System.out.println("Table()");
bowl2.f1(1);
}
void f2(int marker) {
System.out.println("f2(" + marker + ")");
}
static Bowl bowl2 = new Bowl(2);
}
class Cupboard {
Bowl bowl3 = new Bowl(3);
static Bowl bowl4 = new Bowl(4);
public Cupboard() {
System.out.println("Cupboard()");
bowl4.f1(2);
}
void f3(int marker) {
System.out.println("f3(" + marker + ")");
}
static Bowl bowl5 = new Bowl(5);
}
public class StaticInitialization {
public static void main(String[] args) {
System.out.println("Creating new Cupboard() in main");
new Cupboard();
System.out.println("Creating new Cupboard() in main");
new Cupboard();
table.f2(1);
cupboard.f3(1);
}
static Table table = new Table();
static Cupboard cupboard = new Cupboard();
}
/** Output:
Bowl(1)
Bowl(2)
Table()
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
f2(1)
f3(1)
**/
总结:
1. 静态初始化只有在必要的时刻才会进行,static对象首次初始化后不会再次被初始化;
2. 初始化顺序:先static对象(尚未初始化过的),然后才是非静态对象。
3. 即使没有显式使用static关键字,构造器实际上也是静态方法。因此首次创建类对象时(构造器可以视为静态方法),或对象的静态方法/静态域首次被访问时,java解释器必须查找类路径,来定位.class文件。
4. 载入.class文件后,有关静态初始化的所有动作都会执行(静态初始化只在class对象首次加载时进行一次)。
5. 使用new创建对象时,首先在堆上为对象分配足够的存储空间。
6. 这块存储空间被清零,就自动地将类对象中的所有基本类型数据都设置成了默认值(对数字、布尔值、字符型来说都是0),而引用被设置成了null。
7. 执行所有出现于字段定义中的初始化动作。
8. 执行构造器。