提到类加载,不得不先说一下static
在《Java编程思想》当中有这样一段话:
“static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。”
总结一下就是static:方便在没有创建对象的情况下来进行调用(方法/变量)
很显然,被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。
一、static内存使用
static关键字存储在我们的方法区当中的静态常量池当中,static修饰的方法、变量和代码块都是可以被用来共享的
二、static修饰符
重点:static属于类
- 修饰变量:属于类变量,可以被该类的所有实例共享
- 修饰方法:1不能与this共用2 静态方法中不能调用非静态方法 3 非静态方法中可以调用静态方法
- 修饰块:在main()方法前调用。
三、static 加载顺序
首先来一个简单的加载例子:
public class Test extends Base{
static{
System.out.println("test static");
}
public Test(){
System.out.println("test constructor");
}
public static void main(String[] args) {
new Test();
}
}
class Base{
static{
System.out.println("base static");
}
public Base(){
System.out.println("base constructor");
}
}
先来想一下这段代码具体的执行过程,在执行开始,先要寻找到main方法,因为main方法是程序的入口,但是在执行main方法之前,必须先加载Test类,而在加载Test类的时候发现Test类继承自Base类,因此会转去先加载Base类,在加载Base类的时候,发现有static块,便执行了static块。在Base类加载完成之后,便继续加载Test类,然后发现Test类中也有static块,便执行static块。在加载完所需的类之后,便开始执行main方法。在main方法中执行new Test()的时候会先调用父类的构造器,然后再调用自身的构造器。
接下来来一个终极版:
public class InitializeDemo {
private static int k = 1;
private static InitializeDemo t1 = new InitializeDemo("t1");
private static InitializeDemo t2 = new InitializeDemo("t2");
private static int i = print("i");
private static int n = 99;
{
print("初始化块");
j=100;
}
public InitializeDemo(String str) {
System.out.println((k++) + ":" + str + " i=" + i + " n=" + n);
++i;
++n;
}
static {
print("静态块");
n=100;
}
private int j = print("j");
public static int print(String str) {
System.out.println((k++) + ":" + str + " i=" + i + " n=" + n);
++n;
return ++i;
}
public static void main(String[] args) {
InitializeDemo test = new InitializeDemo("test");
}
}
分析一下,首先找到main,发现InitializeDemo 未加载,加载这个类。
在类内加载的顺序是,先加载static,在初始化变量,或者是初始化代码块,最后进行构造函数。
按照顺序加载k 。然后构造t1对象。要初始化,所以执行这个初始化块
{
print("初始化块");
j=100;
}
调用print函数,打印 (在这里有一个细节,在构造t1对象前,已经把类内的static声明的变量提前加载一下,但是并不赋值,是0或者null)
1:初始化块 i=0 n=0
然后初始化非静态变量
private int j = print("j");
打印:
2:j i=1 n=1
然后进行对象的构造,调用构造函数:
3:t1 i=2 n=2
然后按顺序构造t2
4:初始化块 i=3 n=3
5:j i=4 n=4
6:t2 i=5 n=5
然后按顺序往下加载得到:
7:i i=6 n=6
8:静态块 i=7 n=99
9:初始化块 i=8 n=100
10:j i=9 n=101
11:test i=10 n=102