写了这么长时间java,总是不太清楚什么是类的加载,初始化,加载初始化又对应的是我们代码中的哪一段。还有就是静态代码块到底是在什么实际执行的。
首先类加载包括 装载(也叫加载,区别于“类加载”,“加载”是“类加载”的一部分),连接(包括验证、准备、解析),初始化。
1.加载
1)通过一个类的全部限定名来获取定义此类的二进制字节流。
2)将这个字节流所代表的静态储存结构转化为方法去的运行时数据结构
3)在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
注:该3点是取自深入理解Java虚拟机第二版,要我理解无非就是说要找到.class文件(一般情况下)然后读取到内存(方法区),Class本省也是一个对象,他等待对应的实例对象的调用。
2.连接
1)验证,总之就是为加载的class进行验证,包括文件格式验证,元数据验证,字节码验证等等。。
2)准备,准备阶段是正式为类变量(static修饰的变量)分配内存并设置初始值。
该阶段只为静态变量分配内存(方法区),但是“通常情况”变量的值只是赋予初始值,真正的赋值是在类初始化的时候。即
public static int val = 1234; val的值在准备阶段结束后的值为0;而不是1234。
例外情况: public static final int val = 1234; 这时候就会把值设置成1234;
3)解析,没太理解清楚 不解释了。。。
3.初始化
当创建对象(new 或者反射等),调用类的静态方法,使用累的静态字段(已经初始化过值得除外,如final static修饰的常量),子类初始化时, 以及当虚拟机启动某个被 标明为启动类的类(即包含main方法的那个类)时,尽心初始化。 静态变量的复制,静态代码块的执行都在次阶段。
4.自己的代码与jvm执行过程的理解
1)类1
package study.jiazai;
public class A {
public static String in = "in in";
static {
System.out.println(in);
}
public void print(){
System.out.println("print...");
}
}
2)类2
package study.jiazai;
public class Mainlcass {
public static void main(String[] args) {
System.out.println("..............");
A a;//声明定义对象此时执行了1.加载,2.准备阶段
System.out.println("---------------------");
a = new A();//初始化阶段
System.out.println("====================");
a.print();
}
}
3)执行结果
..............
---------------------
in in//说明初始化之后执行的静态代码块
====================
print...
5.困扰我好久的一个问题。
在我们写代码种应该经常写过类似如下的代码
写法1
for(int i = 0 ;i<100;i++){
A a = new A();
a.setString("123456");
a.setName("dashan");
}
写法2
A a=null;
for(int i = 0 ;i<100;i++){
a = new A();
a.setString("123456");
a.setName("dashan");
很久以前有人告诉我要用写法2,当时问了一句为什么记得这样可是省得每次分配内存,那时候也就这样记下了,可是后来根据对JVM的了解,
了解到对象分配后又开始迷惑了,不知道这内存是不是正的省了,是到底怎么省得,今天搜了好多帖子也都没找到具体的答案,不过好在经过看书
以及大家帖子的启发,自己思考了好久感觉终于想通了,拿出来分享下,如果有什么问题欢迎指正讨论。
1.首先一开始我以为是省了对内存,但是想了想不过怎么都是要重新创建多次对象,没有任何我节约。
2.今天终于吧注意力关注到栈内存了,对啊,原来是这样省去了每次循环分配栈内存的步骤。(注 不是省了栈内存,而是省去了没次都要重新分配占内存的步骤)
1)我们知道java的局部变量是占用的栈内存,同时随着局部代码块的结束销毁的。
2)在占中除了操作栈之外,还有另外重要一部分局部变量表,局部变量表中保存的是代码块中每个变量的实际值或者对象引用。(感觉今天主要是这点想通了)
3)基于第二点写法1中每次循环都要在档次循环的栈中(具体指局部变量表)创建内存空间;写法2中在代码块外面把局部变量表中的内存分配好对于循环代码块
它可以算作是一个全局变量只需要分配一次内存就可以在循环中使用了。
3.综上所述,这样的写法应该是提升了分配内存的效率。。。