1、包装类的缓存
2、 String声明的字面量,都是放在字符串常量池中,而常量池JDK6放在永久代、JDK7以后放在堆空间
在JDK6之前,由于常量池在永久代,所以intern调用自后,helloworld生成在永久代,所以str不等于str1
在JDK7之后,由于常量池在堆中,所以intern调用后,常量池中会存放堆中helloworld对象的引用,所以str等于str1
//返回了一个 new String
String str = new String("hello") + new String("world");
str.intern();
String str1 = "helloworld";
System.out.println(str == str1);//false --> true (加上intern() 在str声明之前)
3、class文件的结构
- 魔数
- Class版本
- 常量池
- 访问标识
- 类索引、父类索引、接口索引集合
- 字段表集合
- 方法表集合
- 属性表集合
4、方法调用的字节码指令
- invokevirtual:用于调用对象的实例方法,根据对象的实际类型进行分配(虚方法分派),支持多态。这也是java语言中最常见的方法分配方式
- invokeinterface:用于调用接口方法,他会在运行时搜索由特定对象所实现的这个接口方法,并找出合适的方法进行调用
- invokespecial:用于嗲偶用一些需要特殊处理的实例方法,如实例的初始化方法(构造器)、私有方法、父类方法。这些方法都是静态类型绑定的,不会在调用时进行动态派发,属于静态绑定。
- invokestatic:用户静态方法的调用,这是静态绑定的。优先级大于invokespecial
- invokedynamic:该方法调用动态绑定方法,jdk1.7之后引入的新指令。用于在运行时动态解析出调用点限定符所引用的方法。该指令的分派逻辑是由用户所设定的引导方法决定的
5、自动拆箱,引用类型和基本类型做比较,引用类型会自动拆箱(intValue)程基本类型(拆箱效率高于装箱)
Integer x = 128;
int y = 128;
System.out.println(x == y)
6、类的加载过程
- 装载:把整个字节码文件,加载到内存中,生成Class对象(方法区),数组是动态加载
- 连接
- 验证:就是验证class格式是否是规定的格式
- 准备:为类的静态变量分配内存,默认值
- 解析:符号引用转换为直接引用
- 初始化:为类的静态变量赋予正确的初始值(执行<clinit>()方法)
- 使用
- 卸载
7、触发类的加载,就是主动使用的情况8种,Class.forName和loadClass不同之处在于前者是主动使用
8、双亲委派机制,在ClassLoader中的loadClass方法中体现,为了确保核心API(如String)被正确加载,ClassLoader中定义了perDefineClass方法
9、Tomcat 类加载器本身不遵循双亲委派机制
10、-Xms、-Xmx ,一样大的好处就是为了让其不随便扩容、缩容
11、空间分配担保,就是判断YGC之前,老年代的空间是否能够存放下
12、创建对象的步骤:
- 判断对象类是否加载、连接、初始化
- 分配内存空间
- 解决线程安全问题:CAS、TLAB
- 给对象字段赋初始值
- 设置对象头信息
- 调用构造方法<init>显示赋值