第一章 JVM

1.1 JVM的运行机制

Java程序的具体运行过程如下

  1. Java源文件被编译器编译成字节码文件。
  2. JVM将字节码文件编译成相应操作系统的机器码。
  3. 机器码调用相应操作系统的本地方法库执行相应的方法。

Java虚拟机(JVM,Java Virtual Machine) 包括:
image.png Offer来了 - 图2

1.2 多线程

JVM中的线程与操作系统中的线程是相互对应的。操作系统负责调度所有线 程,并为其分配CPU时间片,在原生线程初始化完毕时,就会调用Java线程的run()执该线程;在线程结束时,会释放原生线程和Java线程所对应的资源。
在JVM后台运行的线程主要有以下几个: Offer来了 - 图3

1.3 JVM的内存区域

image.png

  • 线程私有区域的生命周期与线程相同,随线程的启动而创建,随线程的结束而销毁。
  • 线程共享区域随虚拟机的启动而创建,随虚拟机的关闭而销毁。
  • 直接内存也叫作堆外内存,它并不是JVM运行时数据区的一部分, 但在并发编程中被频繁使用。

    1.3.1 程序计数器:线程私有,无内存溢出问题

    程序计数器是一块很小的内存空间,用于存储当前运行的线程所执行的字节码的行号指示器。它是唯一没有Out Of Memory(内存溢出)的区域。

    1.3.2 虚拟机栈:线程私有,描述Java方法的执行过程

    虚拟机栈是描述Java方法的执行过程的内存模型,它在当前栈帧 (Stack Frame)中存储了局部变量表、操作数栈、动态链接、方法出口等信息。

    1.3.3 本地方法区:线程私有

    本地方法区和虚拟机栈的作用类似,区别是虚拟机栈为执行Java方法服务,本地方法栈为Native方法服务。

    1.3.4 堆:也叫作运行时数据区,线程共享

    在JVM运行过程中创建的对象和产生的数据都被存储在堆中,堆是被线程共享的内存区域,也是垃圾收集器进行垃圾回收的最主要的内存区域。
    由于现代JVM采用分代收集算法,因此Java堆从GC(Garbage Collection,垃圾回收)的角度还可以细分为:新生代老年代永久代

    1.3.5 方法区:线程共享

    方法区也被称为永久代,用于存储常量、静态变量、类信息、即时编译器编译后的机器码、运行时常量池等数据
    image.png

1.4 JVM的运行时内存

JVM的运行时内存也叫作JVM堆,从GC的角度可以将JVM堆分为新生代、老年代和永久代。其中
image.png

  • JVM新创建的对象(除了大对象外)会被存放在新生代,默认占1/3堆内存空间。由于JVM会频繁创建对象,所以新生代会频繁触发MinorGC进行垃圾回收。MinorGC 采用复制算法实现。
  • 老年代主要存放有长生命周期的对象和大对象。老年代的GC过程叫作MajorGC。在老年代,对象比较稳定,MajorGC不会被频繁触发。MajorGC采用标记清除算法实现。
  • 永久代指内存的永久保存区域,主要存放Class和Meta(元数据)的信息。Class在类加载时被放入永久代。Java 8中永久代已经被元数据区(也叫作元空 间)取代。元空间的大小不受JVM内存的限制,只和操作系统的内存有关

1.5 垃圾回收与算法

1.5.1 如何确定垃圾

Java采用引用计数法和可达性分析来确定对象是否应该被回收:
image.png

  • 引用计数法

在Java中如果要操作对象,就必须先获取该对象的引用,因此可以通过引用计数法来判断一个对象是否可以被回收。在为对象添加一 个引用时,引用计数加 1;在为对象删除一个引用时,引进计数减1;如果一个对象的引用计数为 0,则表示此刻该对象没有被引用,可以被回收。引用计数法容易产生循环引用问题。循环引用指两个对象相互引 用,导致它们的引用一直存在,而不能被回收。

  • 可达性分析

为了解决引用计数法的循环引用问题,Java还采用了可达性分析来判断对象是否可以被回收。具体做法是首先定义一些GC Roots对象,然后以这些GC Roots对象作为起点向下搜索,如果在GC roots和一个对象之间没有可达路径,则称该对象是不可达的。不可达对象要经过至少两次标记才能判定其是否可以被回收,如果在两次标记后该对象仍然是不可达的,则将被垃圾收集器回收。

1.5.2 Java中常用的垃圾回收算法

Java中常用的垃圾回收算法有标记清除(Mark-Sweep)、复制(Copying)、标记整理(Mark-Compact)和分代收集(Generational Collecting)这 4种垃圾回收算法,如图
image.png

  • 标记清除算法:会引起内存碎片化的问题,继而引起大对象无法获得连续可用空间的问题。(老年代常采用此方法)
  • 复制算法:解决碎片化问题,但是由于同一时刻只有一个内存区域可用,即可用的内存空间被压缩到原来的一半,因此存在大量的内存浪费。(新生代常采用此方法)
  • 标记整理算法:结合了标记清除算法和复制算法的优点。
  • 分代收集算法:针对不同的对象类型(长生命周期、短生命周期、大对象、小对象),JVM采用了不同的垃圾回收算法,该算法被称为分代收集算法。

1.6 Java中的4种引用类型

在Java中一切皆对象,对象的操作是通过该对象的引用(Reference)实现的。
image.png

  • 强引用:在Java中最常见的就是强引用。在把一个对象赋给一个引用变量时,这个引用变量就是一个强引用。有强引用的对象一定为可达性状态,所以不会被垃圾回收机制回收。因此,强引用是造成Java内存泄漏(Memory Link)的主要原因。
  • 软引用:软引用通过SoftReference类实现。如果一个对象只有软引用,则在系统内存空间不足时该对象将被回收。
  • 弱引用:弱引用通过WeakReference类实现,如果一个对象只有弱引用,则在垃圾回收过程中一定会被回收。
  • 虚引用:虚引用通过PhantomReference类实现,虚引用和引用队列联合使用,主要用于跟踪对象的垃圾回收状态。


1.7 分代收集算法和分区收集算法

1.7.1 分代收集算法

  • 新生代主要存储短生命周期的对象,因此在垃圾回收的标记阶段会标记大量已死亡的对象及少量存活的对象,因此只需选用复制算法将少量存活的对象复制到内存的另一端并清理原区域的内存即可。
  • 老年代主要存放长生命周期的对象和大对象,可回收的对象一般较少,因此JVM采用标记整理算法进行垃圾回收,直接释放死亡状态的对象所占用的内存空间即可。

    1.7.2 分区收集算法

    分区算法将整个堆空间划分为连续的大小不同的小区域,对每个小区域都单独进行内存使用和垃圾回收,这样做的好处是可以根据每个小区域内存的大小灵活使用和释放内存。

1.8 垃圾收集器

JVM针对新生代和老年代分别提供了多种不同的垃圾收集器。针对新生代提供的垃圾收集器有Serial、ParNew、Parallel Scavenge,针对老年代提供的垃圾收集器有Serial Old、Parallel Old、CMS,还有针对不同区域的G1分区收集算法。
image.png

1.9 Java网络编程模型

1.9.1 阻塞I/O模型

1.9.2 非阻塞I/O模型

1.9.3 多路复用I/O模型

1.9.4 信号驱动I/O模型

1.9.5 异步I/O模型

1.9.6 Java I/O

1.9.7 Java NIO

1.10 JVM的类加载机制

1.10.1 JVM的类加载阶段

JVM的类加载分为 5个阶段:加载、验证、准备、解析、初始化。在类初始化完成后就可以使用该类的信息,在一个类不再被需要时可以从JVM中卸载,如图
image.png

1.10.2 类加载器

JVM提供了3种类加载器,分别是启动类加载器、扩展类加载器和应用程序类加载器
image.png

  • 启动类加载器:负责加载Java_HOME/lib目录中的类库,或通过-Xbootclasspath参数指定路径中被虚拟机认可的类库。
  • 扩展类加载器:负责加载Java_HOME/lib/ext目录中的类库,或通过java.ext.dirs系统变量加载指定路径中的类库。
  • 应用程序类加载器:负责加载用户路径(classpath)上的类库。

除了上述3种类加载器,我们也可以通过继承java.lang.ClassLoader实现自定义的类加载器。

1.10.3 双亲委派机制

1.10.4 OSGI

第2章 Java基础

本章将针对常用的Java基础知识展开详细的介绍,具体包含Java的集合、异常分类及处理、反射机制、注解、内部类、泛型、序列化这几部分内容。

2.1 集合

Java的集合类被定义在Java.util包中,主要有4种集合,分别为List、Queue、Set和Map,每种集合的具体分类如图
image.png

2.1.1 List:可重复

List是非常常用的数据类型,是有序的Collection,一共有三个实现类,分别是ArrayList、Vector和LinkedList。

  • ArrayList:基于数组实现,增删慢,查询快,线程不安全
  • Vector:基于数组实现,增删慢,查询快,线程安全。
  • LinkedList:基于双向链表实现,增删快,查询慢,线程不安全。

    2.1.2 Queue

    Queue是队列结构,Java中的常用队列如下

  • ArrayBlockingQueue:基于数组数据结构实现的有界阻塞队列。

  • LinkedBlockingQueue:基于链表数据结构实现的有界阻塞队列。
  • PriorityBlockingQueue:支持优先级排序的无界阻塞队列。
  • DelayQueue:支持延迟操作的无界阻塞队列。
  • SynchronousQueue:用于线程同步的阻塞队列。
  • LinkedTransferQueue:基于链表数据结构实现的无界阻塞队列。
  • LinkedBlockingDeque:基于链表数据结构实现的双向阻塞队列。

    2.1.3 Set:不可重复

    Set核心是独一无二的性质,适用于存储无序且值不相等的元素。对象的相等性在本质上是对象的HashCode值相同,Java依据对象的内存地址计算出对象的HashCode值。如果想要比较两个对象是否相等,则必须同时覆盖对象的hashCode方法和equals方法,并且hashCode方法equals方法的返回值必须相同。

  • HashSet:HashTable实现,无序

  • TreeSet:二叉树实现
  • LinkHashSet:HashTable实现数据存储,双向链表记录顺序

    2.1.4 Map

  • HashMap:数组+链表存储数据,线程不安全。每次遍历的顺序无法保证相同。

  • ConcurrentHashMap:分段锁实现,线程安全。
  • HashTable:线程安全。遗留类。与HashMap类似,不同的是它继承自Dictionary类
  • TreeMap:基于二叉树数据结构。
  • LinkedHashMap:基于HashTable数据结构,使用链表保存插入顺序。

2.2 异常分类及处理

2.2.1 异常的概念

异常指在方法不能按照正常方式完成时,可以通过抛出异常的方式退出该方法,在异常中封装了方法执行过程中的错误信息及原因,调用方在获取该异常后可根据业务的情况选择处理该异常或者继续抛出该异常。

2.2.2 异常分类

在Java中,Throwable是所有错误或异常的父类,Throwable又可分为Error和Exception,常见的Error有AWTError、ThreadDeath,Exception又可分为RuntimeException和CheckedException。
image.png

  • Error指Java程序运行错误,如果程序在启动时出现Error,则启动失败;如果程序在运行过程中出现Error,则系统将退出进程。
  • Exception指Java程序运行异常,即运行中的程序发生了人们不期望发生的事件,可以被Java异常处理机制处理。Exception也是程序开发中异常处理的核心,可分为
    • RuntimeException(运行时异常),指在Java虚拟机正常运行期间抛出的异 常 ,RuntimeException 可以被捕获并处理,如果出RuntimeException,那么一定是程序发生错误导致的。
    • CheckedException(检查异常),指在编译阶段Java编译器会检查CheckedException异常并强制程序捕获和处理此类异常,即要求程序在可能出现异常的地方通过try catch语句块捕获并处理异常。

image.png

2.2.3 异常处理方式:抛出异常、使用try catch捕获并处理异常

异常处理方式有抛出异常和使用try catch语句块捕获并处理异常这两种方式。

  • 抛出异常
  • 使用try catch捕获并处理异常

第9章 设计模式

设计模式(Design Pattern)是经过高度抽象化的在编程中可以被反复使用的代码设计经验的总结。编写符合设计模式规范的代码不但有利于自身系统的稳定、可靠,还有利于外部系统的对接。

9.1 设计模式简介

设计模式是人们经过长期编程经验总结出来的一种编程思想。针对不同的需求,新的设计模式被提出,但设计模式的原则不会变。设计模式有 7个原则:单一职责原则、开闭原则、里氏代换原则、依赖倒转原则、接口隔离原则、合成/聚合复用原则、迪米特法则。 Offer来了 - 图16

  1. 单一职责原则。单一职责原则又称单一功能原则,它规定一个类只有一个职责
  2. 开闭原则。开闭原则规定软件中的对象(类、模块、函数等)对扩展开放,对修改封闭,遵循这个原则的代码在扩展时并不发生改变。
  3. 里氏代换原则。里氏代换原则是对开闭原则的补充,规定了在任意父类可以出现的地方,子类都一定可以出现。
  4. 依赖倒转原则。依赖倒转原则指程序要依赖于抽象(Java中的抽象类和接口),而不依赖于具体的实现(Java中的实现类)。就是要求对抽象进行编程,不要求对实现进行编程
  5. 接口隔离原则。通过将不同的功能定义在不同的接口中来实现接口的隔离,这样就避免了其他类在依赖该接口(接口上定义的功能)时依赖其不需要的接口,可减少接口之间依赖的冗余性和复杂性。
  6. 合成/聚合复用原则。指通过在一个新的对象中引入(注入)已有的对象以达到类的功能复用和扩展的目的。它的设计原则是要尽量使用合成或聚合而不要使用继承来扩展类的功能。
  7. 迪米特法则。指一个对象尽可能少地与其他对象发生相互作用,即一个对象对其他对象应该有尽可能少的了解或依赖。

设计模式按照其功能和使用场景可以分为三大类:创建型模式 (Creational Pattern)、结构型模式(Structural Pattern)和行为型模式(Behavioral Pattern)
image.png
表详细列举了24种常用的设计模型,下面将详细讲解每种设计模式的特点及用法。

9.2 工厂模式的概念及Java实现

  • 定义接口
  • 定义实现类
  • 定义工厂类
  • 使用工厂模式

9.3 抽象工厂模式的概念及Java实现

工厂模式上添加了一个创建不同工厂的抽象接口(抽象类或接口实现),该接口可叫作超级工厂

9.4 单例模式的概念及Java实现

单例模式是保证系统实例唯一性的重要手段。单例模式首先通过将类的实例化方法私有化来防止程序通过其他方式创建该类的实例,然后通过提供一个全局唯一获取该类实例的方法帮助用户获取类的实例,用户只需也只能通过调用该方法获取类的实例。
单例模式的常见写法:

  • 懒汉模式(线程安全) :定义一个私有的静态对象instance,然后定义一个加锁的静态方法获取该对象。
  • 饿汉模式:指在类中直接定义全局的静态对象的实例并初始化,然后提供一个方法获取该实例对象。
  • 静态内部类:通过在类中定义一个静态内部类。
  • 双锁模式:指在懒汉模式的基础上做进一步优化,给静态对象的定义加上volatile锁来保障初始化时对象的唯一性。

9.5 建造者模式的概念及Java实现

建造者模式(Builder Pattern)使用多个简单的对象创建一个复杂的对象,用于将一个复杂的构建与其表示分离,使得同样的构建过程可以创建不同的表示,然后通过一个Builder类(该Builder类是独立于其他对象的)创建最终的对象。

9.6 原型模式的概念及Java实现

原型模式指通过调用原型实例的Clone方法或其他手段来创建对象。

9.7 适配器模式的概念及Java实现

开发中遇到各个系统之间的对接问题,若想在不修改原有代码结构(类的结构)的情况下完成友好对接,就需要用到适配器模式。配器模式的实现中有三种角色:Source是待适配的类,Targetable是目标接口,Adapter是适配器。
image.png
适配器的实现主要分为三类:类适配器模式、对象适配器模式、接口适配器模式。

  • 类适配器模式:在需要不改变(或者由于项目原因无法改变)原有接口或类结构的情况下扩展类的功能以适配不同的接口时,可以使用类的适配器模式。适配器模式通过创建一个继承原有类(需要扩展的类)并实现新接口的适配器类来实现。
  • 对象适配器模式:思路和类适配器模式基本相同,只是修改了Adapter类。Adapter不再继承Source类,而是持有Source类的实例,以解决兼容性问题。
  • 接口适配器模式:在不希望实现一个接口中所有的方法时,可以创建一个抽象类AbstractAdapter实现所有方法,在使用时继承该抽象类按需实现方法即可。(抽象类可以只实现继承实现部分方法)

9.8 装饰者模式的概念及Java实现

装饰者模式(Decorator Pattern)指在无须改变原有类及类的继承关系的情况下,动态扩展一个类的功能。它通过装饰者来包裹真实的对象,并动态地向对象添加或者撤销功能。
在使用装饰者模式时,需要先定义一个待装饰的Source类的source对象,然后初始化构造器Decorator并在构造函数中传入source对象。

9.9 代理模式的概念及Java实现

代理模式指为对象提供一种通过代理的方式来访问并控制该对象行为的方法。在客户端不适合或者不能够直接引用一个对象时,可以通过该对象的代理对象来实现对该对象的访问,可以将该代理对象理解为客户端和目标对象之间的中介者。在代理模式下有两种角色,一种是被代理者,一种是代理(Proxy)。
image.png

9.10 外观模式的概念及Java实现

外观模式(Facade Pattern)也叫作门面模式,通过一个门面(Facade)向客户端提供一个访问系统的统一接口,客户端无须关心和知晓系统内部各子模块(系统)之间的复杂关系,其主要目的是降低访问拥有多个子系统的复杂系统的难度。
image.png

9.11 桥接模式的概念及Java实现

学习重点

image.png插入「脑图」并进行编辑 Offer来了 - 图22

学习资源

课堂PPT

image.png嵌入「本地文件」,在文档中可预览此文件:

脑图(XMind、Mind Manager、Mind Node) 设计文件(PhotoShop、Sketch、Axure) 办公文件(PDF、PPT、Word、Excel、Keynote、Pages、Numbers)

教学视频

image.png嵌入「本地视频」或「在线视频」,如优酷及Bilibili视频:

阅读材料

image.png插入「附件」

学习计划

image.png插入「表格」,可以在表格框里插入对应的图片、附件、状态