面向对象与面向过程

  • 面向对象 易维护,易复用,易扩展
  • 面向过程 性能一般相对较高

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关键字修饰字符数组来保存字符串

todo
问题:注解与反射

注解与反射

接口与抽象类

接口是对行为的抽象,是一种行为的规范
抽象是对类的类的抽象,是一种模板设计

成员变量与局部变量

成员变量
static
成员变量
局部变量
基本数据类型
局部变量
引用数据类型
内存的存储方式 实例(堆内存) 栈内存 堆内存
不会自动赋值

对象相等与引用相等

对象相等比较内存中存放的内容是否相等
引用相等比较指向的内存地址是否相等

==与equals

==判断对象的地址是否相等,即基本数据类型比较值,引用数据类型比较内存地址
equals()同理
重写后的equals一般会用来比较内容
String的equals就是经过重写的

重要

hashcode和equals

介绍

hashcode() 获取哈希码 返回一个int整数 确定对象在哈希表中的索引位置
散列表存储的是键值对,根据键快速的检索出对应的值

例子

hashset如何检查重复

  1. 先计算hashcode值来判断加入的位置
  2. 如何发现重复,调用equals()来判断对象是否相同
  3. 不同则重新散列到其他位置
  4. 这样的优点是大大减少equals的次数,提高执行速度

java值传递

按值调用 方法接收的是调用者提供的值 不能修改
按引用调用 接受的是调用者提供的变量地址 可以修改

java按值调用

方法得到的参数是所有参数值的一个拷贝

  1. //交换拷贝值,num1,2本身不会改变
  2. public class CallByValue {
  3. public static void main(String[] args) {
  4. int num1 = 10;
  5. int num2 = 20;
  6. swap(num1,num2);
  7. System.out.println(num1+","+num2);
  8. }
  9. private static void swap(int a, int b) {
  10. int temp = a;
  11. a = b;
  12. b = temp;
  13. System.out.println("a = " + a + ", b = " + b);
  14. }
  15. }

一个方法不能修改一个基本数据类型的参数,而对象引用作为参数就不一样。

  1. // 外部对引用对象的改变会反映到所对应的的对象
  2. public static void main(String[] args) {
  3. int[] arr = { 1, 2, 3, 4, 5 };
  4. System.out.println(arr[0]);
  5. change(arr);
  6. System.out.println(arr[0]);
  7. }
  8. public static void change(int[] array) {
  9. // 将数组的第⼀个元素变为0
  10. array[0] = 0;
  11. }

一个方法也不能修改一个基本数据类型的参数 数值型或者布尔型

一个方法可以改变一个对象参数的状态

一个方法不能让对象参数引用一个新的对象

线程

image.png
image.png

获取用键盘输入常用的两种方法

Scanner

BufferedReader

  1. public class KeyInput {
  2. public static void main(String[] args) {
  3. // Scanner input = new Scanner(System.in);
  4. // String s = input.nextLine();
  5. // input.close();
  6. BufferedReader input1 = new BufferedReader(new InputStreamReader(System.in));
  7. try {
  8. String s1 = input1.readLine();
  9. } catch (IOException e) {
  10. e.printStackTrace();
  11. }
  12. }
  13. }

注意

IO流

java基础 - 图3

重要

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扩容机制

进程与线程

多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器,虚拟机栈和本地方法栈。
image.png
一个java程序的运行是main线程和多个其他线程共同运行

程序计数器私有

字节码解释器改变程序计数器依次读取指令,实现代码的流程控制
记录当前线程执行的位置

虚拟机栈和本地方法栈私有

为了保证线程中的局部变量不被别的线程访问到,虚拟机栈和本地方法栈是线程私有的

堆和方法区

堆是进程中最大的一块内存,存放新创建的对象
方法区主要用于存放已被加载的类信息,常量,静态变量

多线程

多线程问题

  • 内存泄漏
  • 上下文切换
  • 死锁

    线程的生命周期和状态

  • new

  • runnable
  • blocked
  • waiting
  • time_waiting
  • terminated

上下文切换

cpu采取的策略是为每个线程分配时间片并轮转的形式,当一个线程的时间片用完的时候就会重新处于就绪状态让其他线程使用

线程死锁

  1. 死锁的四个条件

互斥条件
请求与保持条件
不剥夺条件
循环等待条件

  1. 调用start()方法可启动线程并使线程进入就绪状态,直接执行run()方法的话不会以多线程的方式执行
  2. synchronized关键字保证任意时刻只能由一个线程执行

    synchronized关键字

    主要的三种使用方式

  3. 修饰实例方法11

  4. 修饰静态方法
  5. 修饰代码块

本质是对对象监视器monitor的获取

JMM Java内存模型

ThreadLocal

ThreadLocal让每个线程绑定自己的值

线程池

降低资源消耗
提高响应速度
提高线程的可管理性

JVM

线程私有的

  1. 程序计数器
  2. 虚拟机栈
  3. 本地方法栈

    线程共享的

存放对象实例

  1. 方法区

  2. 直接内存

java对象的创建过程

  1. 类加载检查
  2. 分配内存
    1. 指针碰撞
    2. 空闲列表
  3. 初始化零值
  4. 设置对象头
  5. 执行init方法

对象的访问定位

  1. 使用句柄

java堆中划分出一块内存来作为句柄池

  1. 直接指针

速度更快,节省了一次指针定位的时间开销

JVM内存分配与回收

如何判断对象是否死亡

  1. 引用计数法
  2. 可达性分析算法

强引用 软引用 弱引用 虚引用

强引用:必不可少的生活用品 垃圾回收期绝不会回收它
软引用 可有可无的生活用品 内存空间不够就会回收
弱引用 只有弱引用的对象拥有更短暂的生命周期
虚引用