Static 关键字在内存中的图解:
源码:
//写一个人类
class Person
{
private String name;
private int age;
static String country="CN";
public Person(String name,int age)
{
this.name=name;
this.age=age;
}
public void show()
{
System.out.println(Person.country+":"+this.name+":"+this.age);
}
public static void method()
{
System.out.println(Person.country);
}
}
public class Static_Demo2
{
public static void main(String[]args)
{
Person.method();
Person p=new Person("java",32);
p.show();
}
}
内存分析:
1.在内存中划分区域,栈的区域,堆的区域,方法区的区域。(如图1)
2.方法都是存在方法区中的。当StaticDemo2被执行的时候,加载类,StaticDemo2类已经进内存了。
3.先在内存中划分了一片空间,这个类叫做StaticDemo2(如图2)。
这个类里有一个成员方法,StaticDemo2(){}方法加载进来,是这个类中的默认构造函数(如图3)。
4.接着加载静态方法main,是在静态方法区里的,静态区专门存储静态的数据,StaticDemo2类里的静态方法main就是存储在这块静态区里(如图4)。
5.静态区里的方法和非静态区里的方法都是共享的。非静态区里的成员都有一个this,因为非静态区的内容只能被对象调用;而到了静态区里它们都是所属于类名,只能被类名调用。
6.这个时候主函数main进栈(如图5)。
Main方法进栈以后开始运行里面的内容(如图6)。
7.接着运行第一句Person.method();这个是这个类才加载,这个它就开始找classpath路径下有没有Person.class文件,如果没有设置classpath,它就默认在当前路径下找。找到以后就把Person.class文件加载进内存,一加载就在方法区中分配空间了。Person类进内存了,紧接着person的构造函数(Person(Stringname,int age){this.name=name;this.age=age;})加载进来,voidshow(){sop();}也加载进来(如图8),
在静态方法区中static void method(){}也加载进来,staticString country也加载进来了(如图9)。
8.加载完了之后,这个时候,执行第一句:Person.method();是用类名调用,用类名调用只能找静态区。在静态区找,在Person这个所属类的静态区中 ,有静态方法method(),这个时候method方法开始进栈。开始执行method方法,如果有变量开辟栈空间,没有变量直接执行。接着执行语句System.out.println(Person.country);在静态方法区里找Person类里的变量country。执行完之后弹栈(如图10)。
9.接着执行第二句:Person p=new Person(“java”, 20);,这个时候在主函数里多了一个p(如图12),
接着执行右边new person(“java”,20);,new一个person在堆里开辟一块空间(如图13)。
Person对像里有变量name,age,,由于newperson(“java”,20)是调用了person类里的构造方法,所以此时构造函数进栈(如图14)。
进栈以后,person构造函数先有一个this,这this的值是堆里对象的地址0x0056,接着将两个参数“java”,“20”分别赋给person构造函数的局部变量name,age(如图15),
接着执行方法区里的Person构造函数(如图16),
this.name=name;,将局部变量name的值“java”赋给了this所指向的对象的name。this同理。
10.构造函数person()初始化完了之后,它弹栈了,弹完栈了,右边初始化完毕,这个时候将右边的地址值赋给左边的变量p,变量p指向了对象(如图18)。
11.执行第三句:p.show();,方法区里的show()进栈,show进栈,它是非静态的,有所属this,this有p的地址值(如图19)。
接着执行输出语句System.out.println(Person.country+name+age),,执行person.country,在静态区里调用country,打印出country的值。Name,通过this.name在对象里调用,age,通过this.age在对象里调用。输出完以后show就弹栈了。最后的最后,主函数也弹栈了。所有程序结束(如图20)。