JAVA面试知识点

JAVA面试—未完待续

  • 1.计算机基础
    • 1.1. 络7层架构
    • 1.2. TCP/IP
    • 1.3. TCP
      • 三次握手
      • 四次挥手
    • 1.4. HTTP
    • 1.5. HTTPS
    • 1.6. CDN
  • 2.JVM
    • 2.1.类加载过程
      • 2.1.1加载(Load)
      • 2.1.2.链接(Link)
        • 1.验证
        • 2准备
        • 3.解析
      • 2.1.3.初始化(Init)
    • 2.2.类加载器
      • 第一层:启动类加载器
      • 第二层:扩展类加载器
      • 第三层:应用类加载器
      • 自定义类加载器(未完待续)
    • 2.3.JVM内存
      • 2.3.1.堆
      • 2.3.2.虚拟机栈
        • 1.局部变量表
        • 2.操作栈
        • 3.动态连接
        • 4.方法返回地址
      • 2.3.3.元数据区(方法区)
      • 2.3.4.本地方法栈
      • 2.3.5.程序计数器
    • 2.4.对象实例化(new)
    • 2.5.GC(垃圾回收)
      • 2.5.1 标记清除算法(Mark-Sweep)
      • 2.5.2. 复制算法(copying)
      • 2.5.3. 标记整理算法(Mark-Compact)
      • 2.5.4. 分代收集算法
      • 2.5.5.GC 分代收集算法 VS 分区收集算法
      • 2.5.6. GC 垃圾收集器
  • 3.Java
    • 3.1Java基础
      • ==与equals
      • &和&&
      • JAVA内部类
      • JAVA泛型
      • JAVA序列化(创建可复用的Java对象)
    • 3.2Java集合
      • 3.2.1第一类:按照单个元素存储的Collection
        • 1.List集合
          • ArrayList
          • LinkedList
          • Vector
        • 2.Set集合
          • HashSet
          • TreeSet
          • LinkedHashSet
        • 3.Queue集合
      • 3.2.2第二类:按照Key-Value存储的Map
        • 1.HashMap
        • 2.ConcurrentHashMap
        • 3.TreeMap
        • 4.LinkedHashMap
    • 3.3 JAVA并发多线程
      • 3.3.1.线程的生命周期
      • 3.3.2.线程优先级
      • 3.3.3线程种类
      • 3.3.4线程同步
      • 3.3.5线程池
        • 线程池的组成
        • 拒绝策略
        • Java线程池工作过程
        • CyclicBarrier、CountDownLatch、Semaphore的用法
        • AQS(抽象的队列同步器)
      • 3.3.6ThreadLocal
    • 3.4. JAVA锁
      • 3.4.1 乐观锁 VS 悲观锁
      • 3.4.2 自旋锁 VS 适应性自旋锁
      • 3.4.3 Synchronized同步锁
      • 3.4.4 公平锁 VS 非公平锁
      • 3.4.5 可重入锁 VS 非可重入锁
      • 3.4.6 独享锁 VS 共享锁
      • 3.4.7 volatile关键字的作用(变量可见性、禁止重排序)
      • 3.4.8 synchronized和ReentrantLock的区别
      • 3.4.9 锁优化
    • 3.5 JAVA IO/NIO
    • 3.6 JAVA异常
      • Error
      • Exception
        • 检查异常CheckedException
        • 运行时异常RuntimeException
        • 异常处理
          • try-catch-finally
          • throwsThrow和throws的区别:
          • 自定义异常
    • 3.7 JAVA反射
      • Java反射机制
        • 反射机制优缺点
    • 3.8 JAVA算法
    • 3.9 JAVA设计模式
  • 4 Mysql
    • 4.1MySQL 逻辑结构
    • MySQL 4.2 存储引擎
    • MySQL 4.3 索引
    • MySQL 4.3 索引
  • SpringMVC
  • SpringBoot
  • Mybatis
    • **Mybatis的一级缓存原理(sqlsession级别)**
    • **二级缓存原理(mapper基本)**
  • Nginx
  • Dubbo
  • Zookkeeper
  • Redis
  • RabbitMQ

1.计算机基础

1.1. 络7层架构

  1. 链路层:单个0、1是没有意义的,链路层以字节为单位把0和1进行分组,定义数据帧,写入源和目标机器的物理地址、数据、校验位来传输数据。
  2. 络层:根据IP定义 路地址,区分 段。子 内根据地址解析协议进行MAC寻址,子 外进行路由转发数据包,这个数据包即IP数据包。
  3. 传输层:使源端和目的端机器上的对等实体可以进行会话。在这一层定义了 两个端到端的协议:传输控制协议(TCP)和用户数据 协 议(UDP)。TCP是面向连接的协议,它提供可靠的 文传输和对上层应用的连接服务。为此,除了基本的数据传输外,它还有可靠性保证、流量控制、多路 复用、优先权和安全性控制等功能。UDP是面向无连接的不可靠传输的协议,主要用于不需要TCP的排序和流量控制等功能的应用程序。
    4 . 应用层:包含所有的高层协议,包括:虚拟终端协议(TELNET)、文件传输协议(FTP)、电子邮件传输协议(SMTP)、域名服务(DNS)、 上新闻传输协议(NNTP)和超文本传送协议 (HTTP)等。

1.3. TCP

三次握手

首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。 主机A发送FIN后,进入终止等待状态, 服务器B 收到主机 A连接释放 文段后,就立即 给主机A发送确认,然后服务器B就进入close-wait 状态,此时TCP服务器进程就通知高 层应用进程,因而从A到 B的连接就释放了。此时是“半关闭”状态。即A不可以发送给 B,但是B 可以发送给A。此时,若B 没有数据 要发送给A了,其应用进程就通知TCP释 放连接,然后发送给A连接释放 文段,并等待确认。A发送确认后,进入time-wait,注 意,此时TCP连接还没有释放掉,然后经过时间等待计时器设置的 2MSL后,A才进入到 close状态。

1.4. HTTP


传输流程:

  1. 地址解析
    例:http://localhost.com:8080/index.htm 对于这个地址,解析得到的结果如下:
    协议名:http
    主机名:localhost.com
    端口:8080
    对象路径:/index.htm

    然后通过DNS 解析域名localhost.com,得主机的 IP地址。

  2. 封装 HTTP
    将请求数据和本机信息结合,封装成一个HTTP请求数据包

  3. 封装成 TCP
    封装成TCP包,建立TCP连接(TCP的三次握手)

  4. 客户机发送请求命令
    建立连接后,客户机发送一个请求给服务器,请求方式的格式为:统一资源标识符(URL)、协议版本 ,后边是MIME信息包括请求修饰符、客户机信息和可能的内容。

  5. 服务器响应
    服务器接到请求后,给予相应的响应信息,其格式为一个状态行,包括信息的协议版本 、一个成功或 错误的代码,后边是MIME 信息包括服务器信息、实体信息和可能的内容。

  6. 服务器关闭 TCP连接
    一般情况下,一旦 Web 服务器向浏览器发送了请求数据,它就要关闭 TCP 连 接,然后如果浏览器或者服务器在其头信息加入了这行代码 Connection:keep-alive,TCP 连接在发送 后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了 络带宽。

HTTP状态码:
100 Continue(继续)
101 Switching Protocol(切换协议)

成功响应
200 OK(成功)
201 Created(已创建)
202 Accepted(已创建)
203 Non-Authoritative Information(未授权信息)
204 No Content(无内容)
205 Reset Content(重置内容)
206 Partial Content(部分内容)
重定向
300 Multiple Choice(多种选择)
301 Moved Permanently(永久移动)
302 Found(临时移动)
303 See Other(查看其他位置)
304 Not Modified(未修改)
305 Use Proxy(使用代理)
306 unused (未使用)
307 Temporary Redirect(临时重定向)
308 Permanent Redirect(永久重定向)
客户端错误
400 Bad Request(错误请求)
401 Unauthorized(未授权)
402 Payment Required(需要付款)
403 Forbidden(禁止访问)
404 Not Found(未找到)
405 Method Not Allowed(不允许使用该方法)
406 Not Acceptable(无法接受)
407 Proxy Authentication Required(要求代理身份验证)
408 Request Timeout(请求超时)
409 Conflict(冲突)
410 Gone(已失效)
411 Length Required(需要内容长度头)
412 Precondition Failed(预处理失败)
413 Request Entity Too Large(请求实体过长)
414 Request-URI Too Long(请求 址过长)
415 Unsupported Media Type(媒体类型不支持)
416 Requested Range Not Satisfiable(请求范围不合要求)
417 Expectation Failed(预期结果失败)
==服务器端错误 ==
500 Internal Server Error(内部服务器错误)
501 Implemented(未实现)
502 Bad Gateway( 关错误)
503 Service Unavailable(服务不可用)
504 Gateway Timeout ( 关超时)
505 HTTP Version Not Supported(HTTP版本不受支持)

1.5. HTTPS

HTTPS是以安全为目标的 HTTP通道,简单讲是 HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL。其所用的端口 是443。 过程大致如下:

每一种平台的解释器是不同的,但是实现的虚拟机是相同的,这也就是 Java为什么能够 跨平台的原因了 ,当一个程序从开始运行,这时虚拟机就开始实例化了,多个程序启动就会存在多个虚拟机实例。程序退出或者关闭,则虚拟机实例消亡,多个虚拟机实例之间数据不能共享

2.1.类加载过程

类加载是一个将.class字节码文件实例化为Class对象并进行相关初始化的过程。.java源文件在编译后,就会生成JVM(Java虚拟机)能够识别的二进制字节流文件(*.class)。而JVM把Class文件中的类描述数据从文件加载到内存,并对数据进行校验、转换解析、初始化

第一层:启动类加载器

JVM启动时创建,负责加载JAVA_HOMElib目录中的,或通过-Xbootclasspath参数指定路径中的,且被虚拟机认可(按文件名识别,如rt.jar)的类,负责装载最核心的Java类,比如Object,System,String等

第二层:扩展类加载器

负责加载JAVA_HOMElibext 目录中的,或通过java.ext.dirs系统变量指定路径中的类库。加载一些扩展的系统类,比如XML,加密,压缩相关的功能类等

第三层:应用类加载器

主要加载用户定义的classpath路径下的类。
JVM通过双亲委派模型进行类的加载,当然我们也可以通过继承java.lang.ClassLoader实现自定义的类加载器。

双亲委派:

2.3.1.堆

是被线程共享的一块内存区域,创建的对象和数组都保存在 Java 堆内存中,堆的内存空间既可以固定大小,也可运行时动态调整。一般JVM的Xms和Xmx设置成一样大小,避免系统调整堆空间大小时带来的额外压力。是垃圾收集器进行垃圾收集的最重要的内存区域。 由于现代VM采用分代收集算法, 因此Java堆从GC的角度还可以 细分为: 新生代( Eden 区 、 From Survivor 区 和 To Survivor 区 )和老年代

栈帧是用来存储数据和部分过程结果的数据结构,同时也被用来处理动态链接 、方法返回值和异常分派。栈帧随着方法调用而创建,随着方法结束而销毁——无论方法是正常完成还是异常完成(抛出了在方法内未被捕获的异常)都算作方法结束

1.局部变量表

存放方法参数和局部变量的参数。

2.操作栈

初始状态为空的桶式结构栈,方法执行过程中往栈中写入和提取信息。

3.动态连接

每个栈帧中包含一个在常量池中对当前方法的引用,目的是支持方法调用过程的动态连接。

4.方法返回地址

方法执行时有两种退出情况:第一,正常退出,即正常执行到返回字节码指令。第二,异常退出。无论哪种情况,都将返回至方法当前被调用的位置。

2.3.3.元数据区(方法区)

即我们常说的永久代,主要存放 Class 和 Meta(元数据)的信息, 用于存储被 JVM 加载的类信息、常量、静态变量、即时编译器编译后的代码等数据. GC 不会在主程序运行期对永久区域进行清理。所以这 也导致了永久代的区域会随着加载的Class的增多而胀满,最终抛出OOM异常。 JDK8使用元空间替换永久代。
元空间的本质和永久代类似,元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。类的元数据放入 native memory, 字符串池和类的静态变量放入 java 堆中,这样可以加载多少类的元数据就不再由 MaxPermSize控制, 而由系统的实际可用空间来控制。

2.3.4.本地方法栈

本地方法栈类似于虚拟机栈的作用,区别是虚拟机栈执行的是Java方法(也就是字节码)服务,而本地方法栈则为native方法服务,底层调用的c或者c++等其他语言,我们打开jdk安装目录可以看到也有很多用c编写的文件,可能就是native方法所调用的c代码。最著名的本地方法例如System.currentTimeMillis()。

2.3.5.程序计数器

程序计数器是一块很小的内存空间,它是线程私有的,用来存放执行指令的偏移量和行 指示器等。
正在执行 java方法的话,计数器记录的是虚拟机字节码指令的地址(当前指令的地址)。
如果还是Native方法,则为空。
这个内存区域是唯一一个在虚拟机中没有规定任何OutOfMemoryError情况的区域。

2.4.对象实例化(new)

从执行步骤角度分析对象的创建过程:

  1. 确认类元信息是否存在
    当JVM接收到new指令时,首先在元空间内检查需要创建的类元信息是否存在。若不存在,在双亲委派模式下使用当前类加载器以Classloader+包名+类名为Key进行查找对应的.class文件。如果没找到文件就会抛出ClassNotFoundException异常;如果找到则进行类加载,并生成对应的Class对象。
  2. 分配对象内存
    首先计算出对象占用的空间大小,然后分配内存
  3. 设定默认值:
    成员变量值都需要设定默认值,即各种不同形式的零值。
  4. 设置对象头:
    设置新对象的哈希码,GC信息,锁信息,对象所属的类元信息等,这个过程取决于JVM实现
  5. 执行init方法:
    初始化成员变量,执行实例化代码块,调用类构造方法,并把堆内对象的首地址赋值给引用变量。

2.5.GC(垃圾回收)

一个对象如果没有任何与之关联的引用,则说明对象不太可能再被用到,那么这个对象就是可回收对象。

JAVA面试知识点

2.5.1 标记清除算法(Mark-Sweep)

最基础的垃圾回收算法,分为两个阶段,标注清除
标记阶段标记出所有需要回收的对象,清除阶段回收被标记的对象所占用的空间。

该算法最大的问题是内存碎片化严重,后续可能发生大对象不能找到可利用空间的问题。

2.5.2. 复制算法(copying)

为了解决Mark-Sweep算法内存碎片化的缺陷而被提出的算法。按内存容量将内存划分为等大小 的两块。每次只使用其中一块,当这一块内存满后将尚存活的对象复制到另一块上去,把已使用的内存清掉,这种算法虽然实现简单,内存效率高,不易产生碎片,但是最大的问题是可用内存被压缩到了原本的一半。且存活对象增多的话,Copying算法的效率会大大降低。

2.5.3. 标记整理算法(Mark-Compact)

结合了以上两个算法,为了避免缺陷而提出。标记阶段和Mark-Sweep算法相同,标记后不是清理对象,而是将存活对象移向内存的一端。然后清除端边界外的对象。

2.5.4. 分代收集算法

分代收集法是目前大部分JVM所采用的方法,其核心思想是根据对象存活的不同生命周期将内存 划分为不同的域,一般情况下将GC堆划分为老生代(Tenured/Old Generation)和新生代(Young Generation)。老生代的特点是每次垃圾回收时只有少量对象需要被回收,新生代的特点是每次垃圾回收时都有大量垃圾需要被回收,因此可以根据不同区域选择不同的算法。
1.新生代与复制算法
目前大部分JVM的GC 对于新生代都采取Copying算法,因为新生代中每次垃圾回收都要 回收大部分对象,即要复制的操作比较少,但通常并不是按照1:1来划分新生代。一般将新生代 划分为一块较大的Eden空间和两个较小的Survivor空间(From Space, To Space),每次使用 Eden空间和其中的一块Survivor空间,当进行回收时,将该两块空间中还存活的对象复制到另 一块Survivor空间中。

2.老年代与标记复制算法

而老年代因为每次只回收少量对象,因而采用Mark-Compact算法。

  1. JAVA虚拟机提到过的处于方法区的永生代(Permanet Generation),它用来存储class类, 常量,方法描述等。对永生代的回收主要包括废弃常量和无用的类。
  2. 对象的内存分配主要在新生代的Eden Space和Survivor Space的From Space(Survivor目 前存放对象的那一块),少数情况会直接分配到老生代。
  3. 当新生代的Eden Space和From Space空间不足时就会发生一次GC,进行GC后,Eden Space和From Space区的存活对象会被挪到To Space,然后将Eden Space和From Space进行清理。
  4. 如果To Space无法足够存储某个对象,则将这个对象存储到老生代。
  5. 在进行GC后,使用的便是Eden Space和To Space了,如此反复循环。
  6. 当对象在Survivor区躲过一次GC 后,其年龄就会+1。默认情况下年龄到达15的对象会被移到老生代中

2.5.5.GC 分代收集算法 VS 分区收集算法

1.分代收集算法

当前主流VM垃圾收集都采用”分代收集”(Generational Collection)算法, 这种算法会根据 对象存活周期的不同将内存划分为几块, 如JVM中的 新生代、老年代、永久代,这样就可以根据 各年代特点分别采用最适当的GC 算法

  1. 在新生代-复制算法
    每次垃圾收集都能发现大批对象已死, 只有少量存活. 因此选用复制算法, 只需要付出少量 存活对象的复制成本就可以完成收集.
  2. 在老年代-标记整理算法
    因为对象存活率高、没有额外空间对它进行分配担保, 就必须采用“标记—清理”或“标 记—整理”算法来进行回收, 不必进行内存复制, 且直接腾出空闲内存.

2.分区收集算法

分区算法则将整个堆空间划分为连续的不同小区间, 每个小区间独立使用, 独立回收. 这样做的 好处是可以控制一次回收多少个小区间 , 根据目标停顿时间, 每次合理地回收若干个小区间(而不是 整个堆), 从而减少一次GC 所产生的停顿。

2.5.6. GC 垃圾收集器

Java 堆内存被划分为新生代和年老代两部分,新生代主要使用复制和标记-清除垃圾回收算法; 年老代主要使用标记-整理垃圾回收算法,因此 java 虚拟中针对新生代和年老代分别提供了多种不同的垃圾收集器,

1.Serial 垃圾收集器(单线程、复制算法)
Serial(英文连续)是最基本垃圾收集器,使用复制算法,曾经是JDK1.3.1之前新生代唯一的垃圾 收集器。Serial 是一个单线程的收集器,它不但只会使用一个 CPU 或一条线程去完成垃圾收集工 作,并且在进行垃圾收集的同时,必须暂停其他所有的工作线程,直到垃圾收集结束。 Serial 垃圾收集器虽然在收集垃圾过程中需要暂停所有其他的工作线程,但是它简单高效,对于限 定单个 CPU 环境来说,没有线程交互的开销,可以获得最高的单线程垃圾收集效率,因此 Serial 垃圾收集器依然是java虚拟机运行在Client模式下默认的新生代垃圾收集器。
2. ParNew 垃圾收集器(Serial+多线程)
ParNew垃圾收集器其实是Serial收集器的多线程版本,也使用复制算法,除了使用多线程进行垃 圾收集之外,其余的行为和Serial收集器完全一样,ParNew垃圾收集器在垃圾收集过程中同样也 要暂停所有其他的工作线程。

ParNew 收集器默认开启和 CPU 数目相同的线程数,可以通过-XX:ParallelGCThreads 参数来限 制垃圾收集器的线程数。【Parallel:平行的】 ParNew虽然是除了多线程外和Serial收集器几乎完全一样,但是ParNew垃圾收集器是很多java 虚拟机运行在Server模式下新生代的默认垃圾收集器。

3.Parallel Scavenge 收集器(多线程复制算法、高效)
Parallel Scavenge 收集器也是一个新生代垃圾收集器,同样使用复制算法,也是一个多线程的垃 圾收集器,它重点关注的是程序达到一个可控制的吞吐量(Thoughput,CPU 用于运行用户代码 的时间/CPU 总消耗时间,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)), 高吞吐量可以最高效率地利用 CPU 时间,尽快地完成程序的运算任务,主要适用于在后台运算而 不需要太多交互的任务。自适应调节策略也是 ParallelScavenge 收集器与 ParNew 收集器的一个 重要区别。

4.CMS 收集器(多线程标记清除算法)
Concurrent mark sweep(CMS)收集器是一种年老代垃圾收集器,其最主要目标是获取最短垃圾 回收停顿时间,和其他年老代使用标记-整理算法不同,它使用多线程的标记-清除算法。 最短的垃圾收集停顿时间可以为交互比较高的程序提高用户体验。 CMS工作机制相比其他的垃圾收集器来说更复杂,整个过程分为以下4个阶段:

  1. 初始标记 只是标记一下GC Roots能直接关联的对象,速度很快,仍然需要暂停所有的工作线程。

  2. 并发标记 进行GC Roots跟踪的过程,和用户线程一起工作,不需要暂停工作线程。

  3. 重新标记 为了修正在并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记 记录,仍然需要暂停所有的工作线程。

  4. 并发清除 清除GC Roots不可达对象,和用户线程一起工作,不需要暂停工作线程。由于耗时最长的并 发标记和并发清除过程中,垃圾收集线程可以和用户现在一起并发工作,所以总体上来看 CMS收集器的内存回收和用户线程是一起并发地执行。 CMS收集器工作过程:

5.G1 收集器
Garbage first 垃圾收集器是目前垃圾收集器理论发展的最前沿成果,相比与CMS 收集器,G1 收 集器两个最突出的改进是: 1. 基于标记-整理算法,不产生内存碎片。 2. 可以非常精确控制停顿时间,在不牺牲吞吐量前提下,实现低停顿垃圾回收。 G1 收集器避免全区域垃圾收集,它把堆内存划分为大小固定的几个独立区域,并且跟踪这些区域 的垃圾收集进度,同时在后台维护一个优先级列表,每次根据所允许的收集时间,优先回收垃圾 最多的区域。区域划分和优先级区域回收机制,确保 G1 收集器可以在有限时间获得最高的垃圾收 集效率。

3.Java

3.1Java基础

==与equals

== 是直接比较的两个对象的堆内存地址,如果相等,则说明这两个引用实际是指向同一个对象地址的。
两个String对象存储的值是一样的,但有可能在内存里存储在不同的地方.

== 比较的是引用而equals方法比较的是内容。public boolean equals(Object obj) 这个方法是由Object对象提供的,可以由子类进行重写。默认的实现只有当对象和自身进行比较时才会返回true,这个时候和 == 是等价的。String, BitSet, Date, 和File都对equals方法进行了重写,对两个String对象 而言,值相等意味着它们包含同样的字为序列。对于基本类型的包装类来说,值相等意味着对应的基本类型的值一样。

&和&&

1.按位与
按位与: 0 & 1 = 0 ; 0 & 0 = 0; 1 & 1 = 1

2.逻辑与。
&: a == b & b == c 即使a == b 已经是 false了,程序还会继续判断b是否等于c
&&: a== b && b== c 样当a==b 为false则不会继续判断b是否等与c

JAVA内部类

Java类中不仅可以定义变量和方法,还可以定义类,这样定义在类内部的类就被称为内部类。
根据定义的方式不同,内部类分为静态内部类,成员内部类,局部内部类,匿名内部类四种。

静态内部类

定义在类内部的静态类,就是静态内部类。


                                                        

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2020年7月21日
下一篇 2020年7月22日

相关推荐