1. Static(可以修饰成员变量、成员方法、内部类,不能修饰构造器)
静态变量可用来在实例之间进行通信或跟踪该类实例的数目。Java没有全局变量,静态变量有点类似于其他语言的全局变量。静态变量只依附于类,对于不是private类型的静态变量,可以在该类外直接用类名调用:Count.Counter++;
null对象可以访问它所属的类的类成员。
(1)在类中,用static声明的成员变量为静态成员变量,或者叫做:类属性,类变量。 ①它为该类的公用变量,属于类,被该类的所有实例共享,在类被载入时被显式初始化; ②对于该类的所有对象来说,static成员变量只有一份。被该类的所有对象共享; ③可以使用“对象.类属性”来调用,不过,一般都是用“类名.类属性”; ④static变量置于方法区中。 (2)用static声明的方法为静态方法 ①不需要对象,就可以调用(类名.方法名) ②在调用该方法时,不会将对象的引用传递给它,所以在static方法中不可访问非static的成员。 |
系统只初始化static变量还是所有成员变量?在类加载时初始化static变量,在类的初始化时完成所有成员变量的初始化(先static后成员变量)
静态方法的编写与使用时应该注意下列问题:
(1) 静态方法的调用不是通过实例对象进行的。所以在静态方法中没有this指针,不能访问所属类的非静态变量和方法,只能访问方法体内定义的局部变量、自己的参数和静态变量
(2) 子类不能重写父类的静态方法,但在子类中可以声明与父类静态方法相同的方法,从而将父类的静态方法隐藏。另外子类不能把父类的非静态方法重写为静态的。
(3)main()方法是一个静态方法。因为它是程序的入口点,这可以使JVM不创建实例对象就可以运行该方法。
Static变量从属于类,存于类的static区,无static修饰的变量从属于对象。
2. 静态初始化块
一个类中,不属于任何方法体并且以static关键字修饰的语句块,称为静态语句块。因为静态语句块常用来进行类变量的初始化,所以也称为静态初始化程序块。static定义初始化块,初始化块有顺序,位置靠前先执行。语法如下:
[修饰符]{ // 初始化块的可执行代码(定义局部变量,调用其他对象方法,分支,循环等) } |
如果有修饰符则只能是static,称为静态初始化块。没有修饰符为普通初始化块。创建java对象时,系统总是先调用该类里定义的初始化块。初始化块虽然也是java类的一种成员,但它没有名字,没有标识符,因此无法通过类、对象来调用初始化块。初始化块只在创建java对象时隐式执行,而且在执行构造器之前执行。
初始化块和构造器之间的差异:
当java创建一个对象时,系统先为该对象的所有实例属性分配内存(前提是该类已经被加载过了),接着程序开始对这些实例属性执行初始化,其初始化顺序是:先执行初始化块或声明属性时指定的初始值,再执行构造器里指定的初始值。 |
初始化是一段固定执行的代码,它不能接受任何参数。因此初始化块对同一个类所有对象所进行的初始化处理完全相同。 |
初始化块的基本用法:如果有一段初始化处理代码对所有对象完全相同,且无须接受任何参数,就可以把这段初始化处理代码提取到初始化块中。 |
static初始化块:
类初始化块,系统在类初始化阶段执行静态初始化块,而不是在创建对象时,因此静态初始化块总是比普通初始化块先执行。
// JDK 8
class Root{
static {
System.out.println("Root static 初始化块");
} // end static
{
System.out.println("Root 普通初始化块");
} // end
public Root(){
System.out.println("Root 的无参构造器");
} // end constructor
} // end Root
class Mid extends Root{
static {
System.out.println("Mid static 初始化块");
} // end static
{
System.out.println("Mid 普通初始化块");
} // end
public Mid(){
System.out.println("Mid 的无参构造器");
} // end constructor
public Mid(String msg){
System.out.println("Mid 的带参构造器,参数值为 " + msg);
} // end constructor
} // end Mid
class Leaf extends Mid{
static {
System.out.println("Leaf static 初始化块");
} // end static
{
System.out.println("Leaf 普通初始化块");
} // end
public Leaf(){
super("Leaf 调用父类构造器");
System.out.println("Leaf 的无参构造器");
} // end constructor
} // end Leaf
public class Test {
public static void main(String[] args) {
new Leaf();
new Leaf();
} // end main
} // end Test
output:
Root static 初始化块
Mid static 初始化块
Leaf static 初始化块
Root 普通初始化块
Root 的无参构造器
Mid 普通初始化块
Mid 的带参构造器,参数值为 Leaf 调用父类构造器
Leaf 普通初始化块
Leaf 的无参构造器
Root 普通初始化块
Root 的无参构造器
Mid 普通初始化块
Mid 的带参构造器,参数值为 Leaf 调用父类构造器
Leaf 普通初始化块
Leaf 的无参构造器
当JVM第一个主动使用某个类时,系统会在类准备阶段为该类的所有静态属性分配内存;在初始化阶段则负责初始化这些静态属性,初始化静态属性的就是执行类初始化代码或者声明类属性时指定的初始值,它们的执行顺序与源代码中排列顺序相同。
(1)如果希望加载后,对整个类进行某些初始化操作,可以使用static初始化块; (2)是在类初始化时执行,不是在创建对象时执行; (3)静态初始化块中不能访问非static成员; (4)执行顺序:上溯到Object类,先执行Object的静态初始化块,再向下执行子类的静态初始化块,直到我们的类的静态初始化块为止。 |