在一个class
中定义的字段,我们称之为实例字段。实例字段的特点是,每个实例都有独立的字段,各个实例的同名字段互不影响。
还有一种字段,是用static
修饰的字段,称为静态字段:static field
。
实例字段在每个实例中都有自己的一个独立“空间”,但是静态字段只有一个共享“空间”,所有实例都会共享该字段。
public class Main { public static void main(String[] args) { Person ming = new Person("Xiao Ming", 12); Person hong = new Person("Xiao Hong", 15); ming.number = 88; System.out.println(hong.number); hong.number = 99; System.out.println(ming.number); } } class Person { public String name; public int age; public static int number; public Person(String name, int age) { this.name = name; this.age = age; } }
上述代码运行结果为打印: 88 99。为什么?修改 ming.number 为 88 ,打印 hong.number 也是 88;修改 hong.number 为 99,打印 ming.number 也为 99。
对于静态字段,无论修改哪个实例的静态字段,效果都是一样的:所有实例的静态字段都被修改了,原因是静态字段并不属于实例
虽然实例可以访问静态字段,但是它们指向的其实都是Person class
的静态字段。所以,所有实例共享一个静态字段。
因此,不推荐用 实例变量.静态字段
去访问静态字段,因为在Java程序中,实例对象并没有静态字段。在代码中,实例对象能访问静态字段只是因为编译器可以根据实例类型自动转换为 类名.静态字段
来访问静态对象。
推荐用类名来访问静态字段。可以把静态字段理解为描述class
本身的字段(非实例字段)。对于上面的代码,更好的写法是:
Person.number = 99; System.out.println(Person.number);
有静态字段,就有静态方法。用static
修饰的方法称为静态方法。
调用实例方法必须通过一个实例变量,而调用静态方法则不需要实例变量,通过类名就可以调用。
因为静态方法属于class
而不属于实例,因此,静态方法内部,无法访问this
变量,也无法访问实例字段,它只能访问静态字段。
通过实例变量也可以调用静态方法,但这只是编译器自动帮我们把实例改写成类名而已。通常情况下,通过实例变量访问静态字段和静态方法,会得到一个编译警告。
1、静态方法与非静态方法的区别
一个类里面的静态方法直接调用静态方法是正常的,而直接调用非静态方式是会报错的。
原因是因为:static静态方法是和类一起加载的,类存在的时候就存在了。而非静态方法是对象存在(类实例化)之后才存在的,在静态方法里调用非静态方法,相当于在一个存在的方法里调一个不存在的方法,所以会报错。
(1)静态方法属于类所有,静态方法可以通过类名直接调用;而非静态的方法属于实例所有,必须先声明类实例之后才能调用类中的方法。
(2)静态方法的速度快,但是不自动进行销毁,比较占内存。非静态方法的速度相对慢些,但调用完后,立即释放类,可以节省内存,可以根据自己的需要选择是用普通方法还是静态方法。
(3)静态方法是类方法,调用时不需要创建类实例。
(4)静态方法是静态绑定到子类,不是被继承。
(5)非静态方法可以访问类中的任何成员,静态方法只能访问类中的静态成员;
(6)由于静态方法只能访问静态字段,而静态字段是个共享空间,所以如果使用静态方法会存在“数据同步”的问题。
(7)静态方法和静态变量创建后始终使用同一块内存,而使用实例的方式会创建多个内存。
(8)静态方法在类加载(第一次创建一个实例或者调用静态方法会发生类加载)的时候就被初始化了,内存在方法区中被开辟。
执行顺序:
1、父类静态块 --> 子类静态块 --> 父类非静态块 --> 父类构造方法 --> 子类非静态块 --> 子类构造方法
2、当父类或子类中有多个静态方法时按在代码中的顺序执行
public class Father { static { System.out.println("Father中的静态块:1"); } static { System.out.println("Father中的静态块:2"); } { System.out.println("Father中的非静态块"); } public Father() { System.out.println("Father构造方法"); } public static void main(String[] args) { Son son = new Son(); } } class Son extends Father{ static { System.out.println("Son中的静态块:1"); } static { System.out.println("Son中的静态块:2"); } { System.out.println("Son中的非静态块"); } public Son() { System.out.println("Son构造方法"); } }
执行结果就是:F1 - F2 - S1 - S2 - F非静 - F构造 - S非静 - S构造。