⽅法区包含什么以及对象的创建
前⾯的⼏篇都没有太明确地指出⽅法区是什么?现在通过⼀些资料的收集和学习,下⾯做⼀些总结
什么是⽅法区:
⽅法区是系统分配的⼀个内存逻辑区域,是JVM在装载类⽂件时,⽤于存储类型信息的(类的描述信息)。
⽅法区存放的信息包括:
类的基本信息:
1.每个类的全限定名
2.每个类的直接超类的全限定名(可约束类型转换)
3.该类是类还是接⼝
4.该类型的访问修饰符
5.直接超接⼝的全限定名的有序列表
已装载类的详细信息
1. 运⾏时常量池:在⽅法区中,每个类型都对应⼀个常量池,存放该类型所⽤到的所有常量,常量池中存储了诸如⽂字字符串、final变量值、类名和⽅法名常量。
2. 字段信息:字段信息存放类中声明的每⼀个字段的信息,包括字段的名、类型、修饰符。
3. ⽅法信息:类中声明的每⼀个⽅法的信息,包括⽅法名、返回值类型、参数类型、修饰符、异常、⽅法的字节码。
(在编译的时候,就已经将⽅法的局部变量、操作数栈⼤⼩等确定并存放在字节码中,在装载的时候,随着类⼀起装⼊⽅法区。)
4. 静态变量:类变量,类的所有实例都共享,我们只需知道,在⽅法区有个静态区,静态区专门存放静态变量和静态块。
5. 到类classloader的引⽤:到该类的类装载器的引⽤。
6. 到类class 的引⽤:虚拟机为每⼀个被装载的类型创建⼀个class实例,⽤来代表这个被装载的类。
下⾯分析static的内存分配
[java]
public class Dome_Static {
public static void main(String[] args) {
Person p1 = new Person();
p1.name = "xiaoming";
Person p2 = new Person();
p2.name = "xiaohong";
p1.speak();
p2.speak();
}
}
class Person {
String name;
static String country;
public void speak() {
System.out.println("name:"+name+",country:"+country);
}
}
[java]
Output:
name:xiaoming,country:chinese
name:xiaohong,country:chinese
1.⾸先,先加载Dome_Static,然后其main函数⼊栈,之后Person被加载。static声明的变量会随着类的加载⽽加载,所以在内存中只会存在⼀份,实例化多个对象,都共享同⼀个static变量,会默认初始化
2.在栈内存为 p1 变量申请⼀个空间,在堆内存为Person对象申请空间,初始化完毕后将其地址值返回给p1,通过p1.name和p1.country修改其值
3.在栈内存为 p2 变量申请⼀个空间,在堆内存为Person对象申请空间,初始化完毕后将其地址值返回给p2,仅仅通过p2.name修改其值
4.打印show⽅法,进栈,这⾥就不画图了,对于栈相关的概念不清楚的可以看看在之前发的博客。简单⼝述下:p1.show() show⽅法⼊栈,在⽅法的内部有个指向堆内存的this引⽤,通过该引⽤可到堆内存实体,打印country时,可通过该堆内存对象到对应的类,读取对应静态区中的字段值
最后给⼤家⼀道⾯试题练练⼿,要求写出其结果(笔试)
[java]
public class StaticTest {
public static int k = 0;
public static StaticTest t1 = new StaticTest("t1");
public static StaticTest t2 = new StaticTest("t2");
public static int i = print("i");
public static int n = 99;
public int j = print("j");
{
print("构造块");
}
static{
print("静态块");
}
public StaticTest(String str) {
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++n;
++i;
}
public static int print(String str) {
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++i;
return ++n;
字符串常量池存的是实例还是引用?}
public static void main(String[] args) {
StaticTest t = new StaticTest("init");
}
}
结果:
[java]
1:j i=0 n=0
2:构造块 i=1 n=1
3:t1 i=2 n=2
4:j i=3 n=3
5:构造块 i=4 n=4
6:t2 i=5 n=5
7:i i=6 n=6
8:静态块 i=7 n=99
9:j i=8 n=100
10:构造块 i=9 n=101
11:init i=10 n=102
这个留给⼤家去思考,如果⼀眼便能便知道为什么是这样的输出结果,那么静态⽅⾯知识应该⽐较扎实了
提⽰⼀下:
1.加载的顺序:先⽗类的static成员变量 -> ⼦类的static成员变量 -> ⽗类的成员变量 -> ⽗类构造 -> ⼦类成员变量 -> ⼦类构造
2.static只会加载⼀次,所以通俗点讲第⼀次new的时候,所有的static都先会被全部载⼊(以后再有new
都会忽略),进⾏默认初始化。在从上往下进⾏显⽰初始化。这⾥静态代码块和静态成员变量没有先后之分,谁在上,谁就先初始化
3.构造代码块是什么?把所有构造⽅法中相同的内容抽取出来,定义到构造代码块中,将来在调⽤构造⽅法的时候,会去⾃动调⽤构造代码块。构造代码快优先于构造⽅法。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论