- 面向对象与面向过程
- JVM JRE JDK
- Oracle JDK 和 OpenJDK的对比
- overload 和 override
- StringBuffer 和 StringBuilder
- 注解与反射
- 接口与抽象类
- 成员变量与局部变量
- 对象相等与引用相等
- ==与equals
- hashcode和equals
- java值传递
- 线程
- 获取用键盘输入常用的两种方法
- BufferedReader
- IO流
- 重要
- BIO NIO AIO
- 深拷贝 vs 浅拷贝
- 集合
- ArrayList扩容机制
- HashMap扩容机制
- HashSet扩容机制
- 进程与线程
- 多线程
- JVM
- java对象的创建过程
- 对象的访问定位
- JVM内存分配与回收
- 如何判断对象是否死亡
- 强引用 软引用 弱引用 虚引用
面向对象与面向过程
- 面向对象 易维护,易复用,易扩展
- 面向过程 性能一般相对较高
JVM JRE JDK
JDK = JRE + javac
JRE = JVM + java类库
HotSpot 采⽤了惰性评估(Lazy Evaluation)的做法,根据⼆⼋定律,消耗⼤部分系统资源的只有那⼀⼩部分的代码(热点代码),⽽这也就是 JIT 所需要编译的部分。JVM 会根据代码每次被执⾏的情况收集信息并相应地做出⼀些优化,因此执⾏的次数越多,它的速度就越快。JDK 9 引⼊了⼀种新的编译模式 AOT(Ahead of Time Compilation),它是直接将字节码编译成机器码,这样就避免了 JIT 预热等各⽅⾯的开销。JDK ⽀持分层编译和 AOT 协作使 ⽤。但是 ,AOT编译器的编译质量是肯定⽐不上 JIT 编译器的。
Oracle JDK 和 OpenJDK的对比
overload 和 override
StringBuffer 和 StringBuilder
- String 类中使用final关键字修饰字符数组来保存字符串
注解与反射
接口与抽象类
接口是对行为的抽象,是一种行为的规范
抽象是对类的类的抽象,是一种模板设计
成员变量与局部变量
| 成员变量 static |
成员变量 |
局部变量 基本数据类型 |
局部变量 引用数据类型 |
|
|---|---|---|---|---|
| 内存的存储方式 | 类 | 实例(堆内存) | 栈内存 | 堆内存 |
| 不会自动赋值 |
对象相等与引用相等
对象相等比较内存中存放的内容是否相等
引用相等比较指向的内存地址是否相等
==与equals
==判断对象的地址是否相等,即基本数据类型比较值,引用数据类型比较内存地址
equals()同理
重写后的equals一般会用来比较内容
String的equals就是经过重写的
hashcode和equals
介绍
hashcode() 获取哈希码 返回一个int整数 确定对象在哈希表中的索引位置
散列表存储的是键值对,根据键快速的检索出对应的值
例子
hashset如何检查重复
- 先计算hashcode值来判断加入的位置
- 如何发现重复,调用equals()来判断对象是否相同
- 不同则重新散列到其他位置
- 这样的优点是大大减少equals的次数,提高执行速度
java值传递
按值调用 方法接收的是调用者提供的值 不能修改
按引用调用 接受的是调用者提供的变量地址 可以修改
java按值调用
方法得到的参数是所有参数值的一个拷贝
//交换拷贝值,num1,2本身不会改变public class CallByValue {public static void main(String[] args) {int num1 = 10;int num2 = 20;swap(num1,num2);System.out.println(num1+","+num2);}private static void swap(int a, int b) {int temp = a;a = b;b = temp;System.out.println("a = " + a + ", b = " + b);}}
一个方法不能修改一个基本数据类型的参数,而对象引用作为参数就不一样。
// 外部对引用对象的改变会反映到所对应的的对象public static void main(String[] args) {int[] arr = { 1, 2, 3, 4, 5 };System.out.println(arr[0]);change(arr);System.out.println(arr[0]);}public static void change(int[] array) {// 将数组的第⼀个元素变为0array[0] = 0;}
一个方法也不能修改一个基本数据类型的参数 数值型或者布尔型
一个方法可以改变一个对象参数的状态
一个方法不能让对象参数引用一个新的对象
线程
获取用键盘输入常用的两种方法
Scanner
BufferedReader
public class KeyInput {public static void main(String[] args) {// Scanner input = new Scanner(System.in);// String s = input.nextLine();// input.close();BufferedReader input1 = new BufferedReader(new InputStreamReader(System.in));try {String s1 = input1.readLine();} catch (IOException e) {e.printStackTrace();}}}
IO流
重要
BIO NIO AIO
BIO 同步阻塞I/O模型
Blocking I/O
NIO 同步非阻塞的I/O模型
AIO 异步非阻塞的I/O模型
深拷贝 vs 浅拷贝
深拷贝
对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容
浅拷贝
对基本数据类型进行值传递,对引用数据类型,进行引用传递般的拷贝
集合
List Set Map
| List | Set | Map |
|---|---|---|
| 有序 | 无序 | 键值对 |
| 可重复 | 不可重复 | key无序不可重复(set),value无序,可重复(list) |
Arraylist LinkedList
| ArrayList | LinkedList | |
|---|---|---|
| 线程安全 | 均不同步,不保证线程安全 | |
| 底层数据结构 | Object数组 | 双向链表 |
ArrayList扩容机制
HashMap扩容机制
列表长度>阈值=8时<64时,进行数据扩容,>64后将链表转化为红黑树,以减少搜索时间。
HashSet扩容机制
进程与线程
多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器,虚拟机栈和本地方法栈。
一个java程序的运行是main线程和多个其他线程共同运行
程序计数器私有
字节码解释器改变程序计数器依次读取指令,实现代码的流程控制
记录当前线程执行的位置
虚拟机栈和本地方法栈私有
为了保证线程中的局部变量不被别的线程访问到,虚拟机栈和本地方法栈是线程私有的
堆和方法区
堆是进程中最大的一块内存,存放新创建的对象
方法区主要用于存放已被加载的类信息,常量,静态变量
多线程
多线程问题
上下文切换
cpu采取的策略是为每个线程分配时间片并轮转的形式,当一个线程的时间片用完的时候就会重新处于就绪状态让其他线程使用
线程死锁
- 死锁的四个条件
互斥条件
请求与保持条件
不剥夺条件
循环等待条件
- 调用start()方法可启动线程并使线程进入就绪状态,直接执行run()方法的话不会以多线程的方式执行
synchronized关键字保证任意时刻只能由一个线程执行
synchronized关键字
主要的三种使用方式
修饰实例方法11
- 修饰静态方法
- 修饰代码块
本质是对对象监视器monitor的获取
JMM Java内存模型
ThreadLocal
ThreadLocal让每个线程绑定自己的值
线程池
降低资源消耗
提高响应速度
提高线程的可管理性
JVM
线程私有的
存放对象实例
方法区
直接内存
java对象的创建过程
- 类加载检查
- 分配内存
- 指针碰撞
- 空闲列表
- 初始化零值
- 设置对象头
- 执行init方法
对象的访问定位
- 使用句柄
java堆中划分出一块内存来作为句柄池
- 直接指针
速度更快,节省了一次指针定位的时间开销
JVM内存分配与回收
如何判断对象是否死亡
- 引用计数法
- 可达性分析算法
强引用 软引用 弱引用 虚引用
强引用:必不可少的生活用品 垃圾回收期绝不会回收它
软引用 可有可无的生活用品 内存空间不够就会回收
弱引用 只有弱引用的对象拥有更短暂的生命周期
虚引用

