Jvm的类加载机制中,我们说过有一个阶段是初始化(Initialization),这个阶段的应用类加载器(Application or App ClasLoader)会收集所有的静态代码块并执行,而且只执行一次。所以这里有一个误区,很多人认为Java静态代码块是在类被加载时自动执行,这是错误的,需要注意的是,静态代码块只在类加载的初始化阶段执行。
类被加载了,不一定会执行静态代码块,详情看代码:
public class ClassLoaderTest {
public static void main(String[] args) {
System.out.println("main()函数===" + LoaderTest.class);
}
}
class LoaderTest {
static {
System.out.println(">>>静态代码块执行了没有<<<");
}
}
那么,静态代码块是如何执行的呢?
静态代码块会在类加载的初始化阶段执行,而且只执行一次。
如果继承父类,则会先执行父类中的静态代码块,然后再执行子类中的静态代码块;
实例对象时,会先执行父类中的非静态代码块,父类中的构造方法,然后再执行子类中的非静态代码块,子类中的构造方法!
public class Father {
static {
System.out.println(">>>Father静态代码块<<<");
}
{
System.out.println(">>>Father非静态代码块<<<");
}
public Father() {
System.out.println(">>>Father无参构造<<<");
}
}
public class TestSon extends Father {
static {
System.out.println(">>>TestSon静态代码块<<<");
}
{
System.out.println(">>>TestSon非静态代码块<<<");
}
public TestSon() {
System.out.println(">>>TestSon无参构造<<<");
}
public static void main(String[] args) {
System.out.println("TestSon的main()函数");
TestSon son1 = new TestSon();
System.out.println("--------------------");
TestSon son2 = new TestSon();
}
}
静态代码块一般用在什么地方?
1)在项目启动时,加载某个类,对数据进行数据化(如初始化基础数据或数据库连接池)。
// 输出服务器编码
static {
Charset defaultCharset = Charset.defaultCharset();
String name = defaultCharset.name();
System.out.println("\n"+"\t"+"当前服务器采用的字符集是:" + name);
}
2)工具类中使用static静态代码块进行初始化,当第一次访问工具类时,就会先进行初始化(只会执行一次),保存到静态全局属性中,当其他类再次访问时,将直接使用初始化数据(如获取一个单例sessionFactory)。
public class HibernateUtil {
private static final SessionFactory sessionFactory;
private static final ThreadLocal session = new ThreadLocal();
static {
try {
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
}