什么是包装类?为什么需要包装类?
「Java 中有 8 个基本类型,分别对应的 8 个包装类」
- byte -- Byte
- boolean -- Boolean
- short -- Short
- char -- Character
- int -- Integer
- long -- Long
- float -- Float
- double -- Double
「为什么需要包装类」:
- 基本数据类型方便、简单、高效,但泛型不支持、集合元素不支持
- 不符合面向对象思维
- 包装类提供很多方法,方便使用,如 Integer 类 toHexString(int i)、parseInt(String s) 方法等等
引申:
Integer a = 1000,Integer b = 1000,a==b 的结果是什么?那如果 a,b 都为1,结果又是什么?
Integer a = 1000,Integer b = 1000,a==b 结果为「false」
Integer a = 1,Integer b = 1,a==b 结果为「true」
这道题主要考察 Integer 包装类缓存的范围,「在-128~127之间会缓存起来」,比较的是直接缓存的数据,在此之外比较的是对象
JMM 是什么?
JMM 就是 「Java内存模型」(java memory model)。因为在不同的硬件生产商和不同的操作系统下,内存的访问有一定的差异,所以会造成相同的代码运行在不同的系统上会出现各种问题。所以java内存模型(JMM)「屏蔽掉各种硬件和操作系统的内存访问差异,以实现让java程序在各种平台下都能达到一致的并发效果」。
Java内存模型规定所有的变量都存储在主内存中,包括实例变量,静态变量,但是不包括局部变量和方法参数。每个线程都有自己的工作内存,线程的工作内存保存了该线程用到的变量和主内存的副本拷贝,线程对变量的操作都在工作内存中进行。「线程不能直接读写主内存中的变量」。
每个线程的工作内存都是独立的,「线程操作数据只能在工作内存中进行,然后刷回到主存」。这是 Java 内存模型定义的线程基本工作方式。
volatile 有什么作用?
- 1.「保证内存可见性」
- 当一个被volatile关键字修饰的变量被一个线程修改的时候,其他线程可以立刻得到修改之后的结果。当一个线程向被volatile关键字修饰的变量「写入数据」的时候,虚拟机会「强制它被值刷新到主内存中」。当一个线程「读取」被volatile关键字修饰的值的时候,虚拟机会「强制要求它从主内存中读取」。
- 2.「禁止指令重排序」
- 指令重排序是编译器和处理器为了高效对程序进行优化的手段,cpu 是与内存交互的,而 cpu 的效率想比内存高很多,所以 cpu 会在不影响最终结果的情况下,不等待返回结果直接进行后续的指令操作,而 volatile 就是给相应代码加了「内存屏障」,在屏障内的代码禁止指令重排序。