java2021-6-26jvm

rivate static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException(“Only one Looper may be created per thread”); // 保证每一个线程只有一个Looper
}
sThreadLocal.set(new Looper(quitAllowed)); // 这句话就表示只能有一个 static final ThreadLocal sThreadLocal = new ThreadLocal();
ThreadLocal 是用的线程的map 形式 里面有一个这个 形式 ThreadLocalMap (Key,values) 保证了唯一性,设 置为静态的常量就保证了堆空间中只有一个,
而Looper的构造器是私有的 不能哪来new . 如果我哪来new 那不是我们的Looper满天飞,而保证只有一个Looper 所以不能哪来实例化, 而在Looper.prepare中的sThreadLocal.set 时我们就拿来new 了

类的加载过程
首先》当我们写好源代码,进行Classload类中的LoadClass方法进行加载,
》生成字节码文件.class 文件,之后》
类的三个加载阶段
》加载》链接(验证,准备,解析)》初始化

怎么验证的呢:首先是通过java虚拟机去识别我们生成的.class文件
以模数开头的就是java对应的虚拟接文件 模数(cafebabe)

文件格式验证:验证字节流是否符合Class文件格式的规范,如:是否以模数0xCAFEBABE开头、主次版本号是否在当前虚拟机处理范围内等等。

元数据验证:对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言规范的要求;如:这个类是否有父类,是否实现了父类的抽象方法,是否重写了父类的final方法,是否继承了被final修饰的类等等。

字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的,如:操作数栈的数据类型与指令代码序列能配合工作,保证方法中的类型转换有效等等。
符号引用验证:确保解析动作能正确执行;如:通过符合引用能找到对应的类和方法,符号引用中类、属性、方法的访问性是否能被当前类访问等等。

符号引用就是一组符号来描述目标,可以是任何字面量。属于编译原理方面的概念如:包括类和接口的全限定名、字段的名称和描述符、方法的名称和描述符。
符号引用就是一组符号来描述目标,可以是任何字面量。属于编译原理方面的概念如:包括类和接口的全限定名、字段的名称和描述符、方法的名称和描述符。

public class TestClaass {
private int num = 10; // 首先在准备阶段将static的属性分一个内存空间;

static{
	num = 20;
}				
public static void main(String[] args){
	System.out.println(TestClass.num) // 显示的值为20;这是为什么呢  首先在准备阶段 我们会将static类的属性分一个内存空间 ,然后在初始化阶段,首先静态属性会初始化为0
					首先会加载static类型的,然后加载静态代码块,首先这个num的值为10,然后加载静态代码块将其值覆盖为20;所以输出就会输出20;
}

}

public class TestClaass {
private int num = 10; // 首先在准备阶段将static的属性分一个内存空间,并且将指付为0;

static{
	num = 20;
	number = 20;
}
private int number = 10;	//首先在准备阶段将static的属性分一个内存空间,并且将指付为0		
public static void main(String[] args){
	System.out.println(TestClass.num) // 显示的值为20;这是为什么呢  首先在准备阶段 我们会将static类的属性分内存, ,然后在初始化阶段。首先静态属性会初始化为0
					首先会加载static类型的,然后加载静态代码块,首先这个num的值为10,然后加载静态代码块将其值覆盖为20;所以输出就会输出20;

	System.out.println(TestClass.number) // 显示值为10;	
}

}
当我们定义了 public static final int num = 20 类型的静态常量 在准备阶段就会将分配一个内存空间,并且将指设置为20个,并不会在准备阶段将值赋值为0;

双亲委派机制

如果一个类的记载器收到了类的加载请求,它
并不会去先去加载自己的加载器,而是把这个请求委托
给父类的加载器去执行

2.若果父类的加载器还存在其父类的加载器,则进一步向上委托
以此递归,请求最终达到顶层的启动类加载器

3,如果父类加载器可以完成加载任务,就完成任务,倘若父类没有完成类的
加载,子类就会尝试自己去加载,这就是双亲委派机制

加载器有 自定义加载器和引导类加载器
自定义类加载器为(ClassLoaders ,ApplicationLoaders,ExtensionLoaders) 而引导类加载器是 BootStrapClassloaders 而系统加载类是由C++和C 写的 所以我们看不到这个加载器
而自定义加载器是由java 写的

首先会向上委托系统加载器 ApplicationClassLoaders 然后再去委托ExtensionCLassloaders 最后才去委托BootStrapClassLoaders
父类没有不能完成加载,则会让子类去加载,父类没有加载成功,则会由子类或者自己去处理

栈帧的内部结构
1.局部变量表
2.操作数栈
3.动态链接 (或指向运行时常量池的方法引用)
4.方法返回地址 (或方法正常退出或者异常退出的定义)
5.一些附加信息

如果常量池中加载过了相同的字符,则不会再次加载相同的字符
而是在常量池中去寻找相同的字符,将相同字符的地址返回回去

如果当我们字符调用了String.intern()这个方法 就会将字符放入常量池,首先他的会去寻找字符常量池中是否有这个字符,如果没有则会在字符常量池中去创建这个字符,如果有会直接去寻找这个字符的地址

字符串拼接不一定是new StringBuilder
如果
final String str = “a”;
final String str2 = “b”;
String str3 = “ab”;
String str4 = str+str2;
System.out.println(str3==str4); // 显示true;
因为当我们将字符设置了final的话 就会放在常量池中 而不是放在字符常量池中
如果我们没有设置final 则会在new StringBuiler

 String str = "a";   	
 String str2 = "b";
String str3 = "ab";
String str4 = str+str2;   底层会再去创建一个StringBuilder的对象,调用append方法将 会加载栈帧中调用当前栈帧里面的局部变量表中的地址 添加在append方法中,然后调用toString方法 其实toString方法底部就是重新创建了一个String的对象 其实就是new 了一个String类 ,然后再讲地址付给str4,所以 我们new 了一个对象出来,其实就是在内存中创建了一个空间,
System.out.println(str3==str4); // 显示false 因为地址不同 

第三种方法 String str = “a”;
String str2 = “b”;
String str3 = “a”+“b”;
String str4 = “ab”;

str3这种方法其中在编译时就做了代码编译优化,所以 str4首先他的会去寻找字符常量池中是否有这个字符,如果没有则会在字符常量池中去创建这个字符,如果有会直接去寻找这个字符的地址
System.out.println(str3==str4); // 返回为True;

boolean char byte 都是 占用4个字节 jvm 字节在这个3个当成一个用,直接使用int 类型的
将他们放在1个slot位置,占用4个字,而long double 都是占用8个字节 占用2个slot槽位,float占用1个slot 槽位,占用4个字节

局部变量压栈 指令 xload_ (x为a,i ,l,f,d,a,n为0到3)
xload_ (x为a,i,l,f,d,e) 在这里的x的取值表示数据类型 比如iload_1、fload_0、aload_0等指令,其中aload_n表示将一个对象引用压入栈中
a为引用类型,i是整形,l为long类型,f为浮点类型
xload_ n 表示0,1,2,3 其中 这都是在局部变量表中,xload是将局部变量表中,将这些slot槽位压栈到操作数栈中。
当n大于3时,xload后面佩戴一个操作数 xload表示操作指令,例如 xload 4 将第4个压入操作数栈

常量入栈指令 指令const :用于特定的常量入栈,入栈的常量在指令本身理,指令有iconst_(i 从-1到5)
iconst_<1> (1从0到 1)
fconst_(f从0到2)
dconst_(d从0到1)
aconst_null
当iconst的的 大于5时 就将引入指令push 系列 加入 定义 int j =4 对应的指令 iconst_4 而定义 int j =6 时 就会引用bipush 6

bipush接受8为整形作为参数 sipush接受16为整数,它们都将参数压入操作数栈中 bipush接受的范围(-128,127)范围 sipush接受的范围为(-32768,32767)
	
当超过sipush的接受范围我们将用于ldc系列 接受8的参数,该参数指向常量池中的int,float,String的索引位置,将指定的内容压入局部变量表中的操作数栈中
类似的还有ldc_w将接受2个8位参数的能支持的索引范围大于ldc
如果要压入的元素是long 或者是double的类型,则会用ldc2_w ,2代表2个槽位
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值