作为了一个刚学习的java的菜鸟,总是有一万个为什么,然后以为懂了,其实可能是半懂不懂,或者是经不起考验的半桶水,记录初级阶段自己想法,为了可以回顾一个有迹可循的学习历程,形成好的学习方法和思路,提高学习效率,并希望逐级建立自己知识体系。
首先jvm执行class文件,需要把class文件(二进制流)加载进来,从菜鸟的角度来说,把它看着是一个图纸根据字符集对应翻译成0、1代码更加贴切,有了图纸我们才能在堆(heap)中创建(new)对应的实例,class首先会以二进制流加到jvm内存中方法区,那么这时需要注意了,内存并不是只做一个翻译和加载的事情。
内存加载类分以下内容:
一、首先就是代码加载,class中分为成员变量、成员函数(局部、语句),首先根据成员是否为静态,分为加载到静态区和非静态区。
1、首先静态成员变量进来都是默认值,比如int是0,string是null。
以代码说明:
public class StaticTest {
<span > </span>
<span > </span>static int first = show("first");
<span > </span>
<span > </span>static int last = 100;
<span > </span>
<span > </span>int n = 200;
<span > </span>
<span > </span>static int show (String s){
<span > </span>System.out.println(s+"==========="+"last:"+last);
<span > </span>return 1;
<span > </span>}
<span > </span>public static void main(String[] args) {
<span > </span>
<span > </span>}<span > </span>
}
结果:first===========last:0
说明:首先我们看到输出语句,说明执行的是show("first"),但是输出last等于0,第一,说明last变量已经在内存中,第二,last值等于0,说明没有执行100的赋值语句。
所以静态成员变量是先默认初始化,然后从上到下再执行赋值符右边的语句(非常量),最后赋值给左边的成员变量。
2、非静态成员变量的赋值和静态不同
public class StaticTest {
<span > </span>
<span > </span>static int st1= show("static");
<span > </span>
<span > </span>int n = show("not static");
<span > </span>
<span > </span>static int show (String s){
<span > </span>System.out.println(s+"===========");
<span > </span>return 1;
<span > </span>}
<span > </span>public static void main(String[] args) {
<span > </span>
<span > </span>}<span > </span>
}
结果:static===========
说明:以上输出语句只有一条且为static开头,说明只调用了show("static"),至少非静态成员变量加载时不会调用执行右边的方法,那么我猜非静态成员变量加载时有两种可能
1:直接等于右边"show("not static")"语句,但不会执行它。
2:可能会先默认值0,然后初始化为语句。
3、举一个特殊的例子,截取在网上看到的代码,说是alibba的试题:
public class StaticTest {
static StaticTest st = new StaticTest();
int n = show("not static");
static int show (String s){
System.out.println(s+"===========");
return 1;
}
public static void main(String[] args) {
}
}
结果:not static===========
说明:该实例竟然输出了"not static",那么究竟是怎么回事,我的理解是在执行第一条语句的右边"new StaticTest"创建对象时,需要在堆中生成一个n变量,那么这时就需要执行右边的值了。
思考:为什么java的jvm会这样处理,我想是static的特性决定,因为static的类成员,可以直接通过类名调用,在别的类中调用,当然希望拿过来的时候直接使用,而不是
用的时候,你成员变量才去执行语句;这样在类加载过程中静态成员变量就会直接运算右边语句获取最终的值。而非静态成员变量是对象所特有的,只有在创建对象是才会
去执行初始化。这个思考方式有点牵强和缺陷,为什么静态变量不在调用时执行初始化。先记录之,以后如果深入了解再修正。
二、执行静态代码块,
public class StaticTest {
<span > </span>
<span > </span>static{
<span > </span>System.out.println("static block1");<span > </span>
<span > </span>}
<span > </span>
<span > </span>static int st1 = show("static var");
<span > </span>
<span > </span>static{
<span > </span>System.out.println("static block2");<span > </span>
<span > </span>}
<span > </span>
<span > </span>static int show (String s){
<span > </span>System.out.println(s+"===========");
<span > </span>return 1;
<span > </span>}
<span > </span>public static void main(String[] args) {
<span > </span>
<span > </span>}<span > </span>
}
static block1
static var===========
static block2
说明:静态代码块和static成员变量的优先级是一样的,按代码从上到下执行。这里面暂时没有考虑父类的加载。