静态代码块和实例初始化块
一:静态代码块
静态代码块的特点
- 在类加载的时候执行,只会执行一次;
- 所有静态代码块和静态变量的优先级一样,执行顺序按照代码的编写顺序;
- 执行静态代码块和静态变量之前,先扫描类里面的静态变量,并将其赋值为"0";
如下例:
public class Person {
static {
System.out.println("静态代码块");
}
static int a;
Person(){
System.out.println("Person类的构造器");
}
public static void main(String[] args) {
Person person1 = new Person();
Person person2 = new Person();
System.out.println(Person.a);
}
}
如图所示,new了两个Person类的实例,但是只调用了一次静态代码块,这也证明了静态代码块只在类加载的时候被调用,而且只调用一次。
再来看看下面这个例子:
public class Test {
static {
cnt = 6;
}
static int cnt = 100;
public static void main(String[] args) {
System.out.println("cnt = " + cnt);
}
static {
cnt /= 2;
}
}
这个例子验证了静态代码块和静态变量的优先级是一样的,调用顺序以代码的编写顺序为标准;执行Test类的时候先扫描Test类,找到静态变量cnt,将其赋值为0,随后执行静态代码块cnt=6;其次执行静态变量赋值cnt=100;然后执行静态代码块cnt/2; 类加载完后cnt=50;所以最后输出50;
二:实例初始化块:
实例初始化块与静态代码块不同的是它可以被执行多次,每次new一个含实例初始化块的对象都会执行。
- 实例初始化块在每次调用构造方法之前首先调用它。
public class Test {
{
System.out.println("实例初始化块");
}
Test(){
}
public static void main(String[] args) {
Test test1 = new Test();
Test test2 = new Test();
}
}
三:静态代码块和实例初始化块呆在一起?
静态代码块是类加载的时候被调用,实例化初始化块是调用构造器之前被调用,也就是说,如果一个程序运行时即使没有实例化类,也会调用其中的静态代码块,但实例初始话块只有在对象被实例化的时候才会先于构造器被调用,所以静态代码块是先于实例初始化块调用的。
举例:
public class Person {
static {
System.out.println("静态代码块");
}
{
System.out.println("实例初始化块");
}
Person(){
System.out.println("Person类的构造器");
}
public static void main(String[] args) {
Person person = new Person();
}
}
四:静态代码块在含有继承关系的类中?
只要我们掌握了静态代码块和实例初始化块的调用时间,不论在含有继承关系的类中还是其他的关系中都能够清晰其调用顺序。
举例:
public class Person {
static {
System.out.println("Person静态代码块");
}
{
System.out.println("Person实例初始化块");
}
Person(){
System.out.println("Person类的构造器");
}
}
public class Student extends Person{
static {
System.out.println("Student的静态代码块");
}
{
System.out.println("Student的实例初始化块");
}
Student(){
System.out.println("Student的构造器");
}
}
public class StaticTest {
@Test
public void test1(){
Student student = new Student();
}
}
总结:
父类静态变量和静态代码块 > 子类静态变量和静态代码块 > 父类实例成员和父类实例初始化块 > 父类构造方法 > 子类实例成员和子类实例初始化块 > 子类构造方法。