Java二轮复习

Java二轮复习

跟着牛客的高频问题

Java基础知识

1、说说多线程

  • 线程和进程的区别
    • 进程是程序执行的基本单位,线程是程序执行的最小单位,一个进程包括多个线程
    • 多个线程共享进程的资源(堆、方法区),线程又有一些自己的资源(程序计数器、本地方法栈、虚拟机栈)
  • 多线程的优势
    • 多核优势,可以在多个cpu上运行
    • 减少了响应时间,多线程执行不同任务
    • 提高cpu的利用率,一个线程阻塞另外的线程可以继续运行
    • 总之:提高了系统的并发能力和性能
  • 多线程的缺点
    • 死锁问题:两个及以上线程相互请求对方的资源
    • 内存泄漏:ThreadLocal(Value的强引用)
    • 线程安全(同步问题):锁

2、说说怎么保证线程安全

  • java在juc下提供很多种方式来保证线程安全,较为常用的有
    • 原子类
      • 保证原子性,通过无锁机制实现(比较并替换,CAS),具体是调用了unsafe类,用c++实现的
    • Volatile关键字
      • 保证有序性和可见性,具体实现是依赖于java的内存模型(JMM)
      • 可见性是应用了cpu的缓存一致性原则,当一个cpu上的变量发生改变,将他置为M(修改)并刷回内存,其他cpu置为I,不可用,重新从内存种读取该变量
      • 有序性是用了读写屏障实现,避免指令重排
      • synchronized
        • 关键字,本来是重量级锁,后面做了锁的优化(锁升级),依赖与对象头中的markword字段
      • Lock
        • api,AQS实现,双向阻塞队列
    • ThreadLocal
      • 线程单独存储,变量隔离
    • 并发工具
      • Semaphore
      • countdownlatch
      • cyclebarrier

3、请说说你对反射的了解

  • 反射是什么:在程序运行期间可以获取任意一个类的方法和属性信息
  • 实现原理:类在加载时创建了Class的对象,存储了类的信息
  • 优缺点
    • 优点是使程序更加灵活
    • 缺点是破坏了程序的封装性
  • 方式
    • 对象.getClass()
    • 类.class
    • Class.forName()
  • 场景:string aop中利用的动态代理模式

4、请你说说ArrayList和LinkedList的区别

  • 数据结构方面:数组、双向链表
  • 存储:要存后面扩容的部分、要存前后指针
  • 查找:随机查找、中间和头尾
  • 插入和删除:移动/扩容、直接插入

5、你知道哪些线程安全的集合?

  • vector、hashtable:synchronized实现的,性能比较差
  • Collections.synchronizedXXX():用的也不多
  • CopyOnWriteArrayList、ConcurrentHashMap、BlockingQueue:lock

6、ConcurrentHashMap

  • 数据结构:
    • jdk1.8前:segment分段数组+hashentry数组+链表
    • jdk1.8后,node数组+链表,链表数量>8会转成红黑树
  • 锁的实现
    • 1.8前是分段锁,用的reentrantlock
    • 1.8后是通过cas+syn锁头节点的形式
  • 多线程的扩容
    • 先扩容,再插入;每个线程承担一部分工作

7、说说你了解的线程同步方式

  • 通过锁来同步,往底层讲:互斥量、信号量、事件;在java中实现同步通过:锁、volatile关键字、并发组件、并发容器
  • 锁的分类:乐观和悲观
  • 两种不同的锁:syn和lock
    • syn锁的升级,对象头的markword
      • 无锁01
      • 偏向锁01,偏向锁位置1
      • 轻量级00:双向绑定+自旋
      • 重量级10:object Monitor
    • reentrantlock:aqs,双向阻塞队列
  • 其他分类:按功能
    • 公平、非公平
    • 可重入
    • 读写

8、String、StringBuffer、StringBuilder有什么区别

  • 是否可变
    • string是final修饰的数组,不可变长,类也是被final修饰不可继承
  • 是否是线程安全的:stringbuffer线程安全
  • 效率

9、请你说说HashMap底层原理

  • 数据结构:node数组+链表/红黑树
  • 扩容
    • 三大参数
    • 2^n

10、说说你了解的JVM内存模型

  • 类的加载子系统
    • 根据类的限定名加载
      • 类的加载:双亲委派机制,将二进制流转为方法区的数据结构并在堆创建class对象
      • 类的连接:准备(静态变量初始值)、验证(格式)、解析(符号引用转为直接引用)
      • 类的初始化:静态变量的赋值
  • 字节码执行引擎:执行加载类方法中的指令
  • 运行时数据区
    • 进程
      • 堆:gc堆、字符串常量池、静态变量
      • 方法区:类元信息、运行时常量池、JIT缓存
    • 线程
      • 程序计数器:用于线程上下文切换和命令的执行
      • 虚拟机栈:栈帧(动态链接、方法返回地址、操作数栈、局部变量表)
      • 本地方法栈
    • 直接内存(元空间)

11、说说JVM的垃圾回收机制

  • 分代收集
    • 建立在3个分代假说上
      • 弱分代假说:绝大多数对象生命周期很短
      • 强分代:经历过多次垃圾收集的越难消亡
      • 跨代引用:跨代引用的占少数
    • 分类
      • 部分收集
        • 新生代
          • 标记复制:对象生命周期通常很短
          • 分代年龄> 15进入老生代,但要先做分配担保
          • 垃圾收集器:serial、ParNew、Parallel Scavenge
        • 老生代
          • 标记清除、标记整理:存活的对象比较多
          • 垃圾收集器:serial old、Parallel Old、cms
      • 混合收集
        • G1,新生代和老生代一起收集
        • 因为堆的划分是以逻辑划分的,每个区域成region
      • 整堆收集
        • 收集堆和方法区
        • 场景
          • 调用system.gc()
          • 分配担保失败
  • 收集器的组合
    • Serial + Serial Old,是客户端模式下常用的收集器
    • ParNew+CMS是服务器端
    • Parallel Scavenge + Parallel Old (吞吐量,jdk1.8默认)

12、说说类加载机制

  • 类加载
    • 二进制流转为方法区的数据结构,在堆中创建class对象
    • 双亲委派机制
      • 防止类的重复加载,保证了java包中的类不被破坏
      • 先交给父类去加载
      • BootstrapClassLoader、ExtensionClassLoader、AppClassLoader
  • 类连接
    • 验证:格式
    • 准备:静态变量分配内存设置初始值
    • 解析:符号引用转直接引用
  • 类的初始化:静态变量赋值
  • 这两个不是但也属于类的生命周期(使用、卸载)

13、请你说一下抽象类和接口的区别

  • 强调的概念不一样
    • 接口是对对象行为的约束,抽象类是对对象特征的概述
  • 抽象类中可以定义各种变量,但接口中只能定义不能修改的静态常量
  • 单继承多实现
  • 方法上,接口没有构造方法抽象函数有(jdk1.8后接口也有默认方法和静态方法,所以这个不算)

14、==与equals()的区别

  • 基本数据类型:==比值,equals不行
  • 引用数据类型
    • ==比较的是地址
    • equals没重写前是地址,重写后是值(重写是不是要写hashcode)

15、说说synchronize的用法及原理

  • 作用位置
    • 方法上(Acc_synchronized)
    • 代码块上(monitor enter、monitor exit)
    • 本质:作用在对象上
  • 锁升级
    • 原理是利用对象头mark word字段
    • 无锁01,用cas来获取变量
    • 偏向锁01,偏向位1,对象头保存经常获取/访问的线程id
    • 轻量级锁00,当有两个以上的线程进行竞争的时候升级,利用mark word存储线程的栈中的lock record,然后线程指向对象,实现双向绑定,取余线程自旋
    • 重量级锁10,当自旋的数量超过1个的时候升级成重量级锁,原理是创建对象的objectMonitor对象,并在markword中指向他。维护了两个队列,一个是等待队列,一个是阻塞队列,这也是为什么wait和notify为什么要放在同步代码块,因为也是借助objectmonitor实现的

16、说说你对AQS的理解

  • AQS队列同步器,是用来构建锁的基础框架。Lock锁基本是都是用AQS实现的
  • 运用了设计模式中模板方法的思想,锁的实现需要继承并重写对应的方法
  • 实现原理上
    • 维护了一个FIFO的队列(双线链表),线程来了之后如果是公平锁就加入阻塞队列,非公平锁就先看当前锁是否可以获取,可以就用否则加入阻塞队列
    • 使用一个volatile关键字表示锁的状态,0表示可以获取,线程通过CAS获取锁

17、Java哪些地方使用了CAS

  • 原子类、AQS、并发容器(ConcurrentHashMap)

18、说说JVM的垃圾回收算法

  • 标记清除:内存碎片
  • 标记复制:内存开销大
  • 标记整理:stw

19、说说static修饰符的用法

  • 修饰的对象:类、方法、变量和代码块
    • 静态内部类,可以通过外部类.内部类的方法访问
    • 静态方法,只能访问静态变量和方法
    • 静态代码块,类加载时执行,可以访问静态变量
      • 静态代码块在类加载时执行,并且只执行一次
      • 直接放在类中,不放方法里面
    • 静态变量,属于类

20、说说线程的状态

  • 创建、就绪、运行、阻塞、等待、等待超时、终止
  • 创建的方式
    • 继承Thread类
    • 实现Runnable接口
    • 实现Callable接口

21、说说你对ThreadLocal的理解

  • 作用:每个线程有自己单独的资源,避免多线程间共享
  • 原理:
    • 每个线程中有一个ThreadLocalMap,key就为ThreadLocal,value为存储的具体的值
    • key为弱引用,避免线程结束后因强引用无法回收ThreadLocal造成内存泄漏
    • value为强引用,所以用完要及时进行remove,否则会造成内存泄漏

22、synchronized和Lock有什么区别

  • syn是关键字,lock是接口
  • 使用方式:
    • syn是隐式锁,自动释放,可以作用于方法、同步代码块
    • lock是显示锁,需要手动加锁和释放
  • lock可以获取锁的状态、等待可中断
  • 实现方式:ObjectMonitor、AQS

23、说说volatile的用法及原理

  • 并发特性
    • 原子性(×)
    • 可见性(√)
    • 有序性(√)
  • JMM:java内存模型
    • 线程将变量拷到本地进行操作(read、load)(store、write)(lock、unlock)(use、assign)
  • volatile关键字
    • 可见性:CPU的缓存一致原则,当一个变量发生改变就置为(M修改),其余置为(I无效),当其他线程使用时需要重新从内存中加载
    • 有序性:禁止指令重排,指令执行时编译器会根据指令的相关性进行重排序,java中通过读写屏障来保证指令的有序性,既在读操作后加(loadload和loadstore),在写操作前后加(storestore和storeload)

24、请你说一下final关键字

  • 作用地方
    • 类:类不能继承
    • 方法:方法不能重写
    • 引用变量:不能重新指向(地址不能变)
    • 基本变量:不能改变值

25、请你说说重载和重写的区别,构造方法能不能重写

  • 重载:方法名相同,返回值、参数类型、参数数量都可能不一样
  • 重写:子类重写父类的方法,方法内容可以不同其余都相同
  • 构造方法不能重写

26、请说说你对Java集合的了解

  • Collection
    • List
    • Set
    • Queue
  • Map
    • HashMap
    • TreeMap
    • HashTable

27、请你说说IO多路复用

  • 定义:单个进程或者线程可以处理多个IO请求
  • 实现原理
    • Linux提供了3种方式:select、poll、epoll,本质上是让操作系统内核缓冲IO数据,让单个进程/线程监视这些文件描述符
    • select通过将文件描述符的数组拷贝到内核态,然后轮询的方式查看是否有数据返回
      • 缺点
        • 每次将文件描述符拷到内核态,开销大
        • 轮询的方式查看
        • 支持的文件描述符个数有限
    • poll将底层数据结构改成了链表,解决了文件描述符个数/重用的问题
      • 缺点:轮询、内核切换
    • epoll:直接在内核中创建一个结构体eventpoll,当有数据来的时候内核会将数据放入就绪队列并通知进程/线程进行读取
      • 数据结构:
        • rbr:红黑树构建的文件描述符
        • rdlist:就绪队列
        • wq:等待队列
      • 命令
        • epoll_create:创建结构体
        • epoll_ctrl:将文件描述符(红黑树)添加/删除/修改
        • epoll_wait:内核返回就绪事件
      • 模式
        • 水平触发LT:一次没拿完就会再通知
        • 边缘触发ET:一次没拿完就下次有数据来了再通知

28、Java 8的新特性

  • lambda表达式:结合函数式接口,简化了代码,将函数作为参数进行传递
  • stream流式计算:将元素或者集合转换成流进行运算
  • datetime时间类:时区问题、格式化问题(日期与时间分离)
  • optional:Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
  • 允许在接口中定义默认的方法,用default修饰

29、请你说说泛型、泛型擦除

  • java中的泛型属于伪泛型,主要的作用是在编译的时候进行类型检查,并且可以将类型自动转换;
  • 在编译期间所有的范型信息会被擦除,被称为泛型擦除
  • 泛型是可以通过反射机制破坏的

30、说说你了解的线程通信方式

  • Monitor
    • 如果是采用synchronized关键字进行同步,则需要依赖Monitor(同步监视器)实现线程通信
    • 由于Monitor实现了等待队列,所以可以使用wait、notify、notifyAll来通信
  • Condition
    • 如果是采用Lock对象进行同步,则需要依赖Condition实现线程通信
    • Lock锁使用Condition可以创建多个等待队列,所以可以做到选择通知,await、signal、signalAll

31、请你说说JUC

  • java.uilt.concurrent包,下面包含一系列的并发相关的工具,比如:原子类、锁(Lock)、并发容器、并发工具、线程池(ThreadPoolExecutor)等

32、请你说说HashMap和Hashtable的区别

  • 数据结构上的区别:hashmap使用node数组+链表+红黑树的方式进行存储,hashtable使用的是node数组+链表的方式
  • 扩容时的区别:hashmap默认是16,如果有设置初始值,默认扩到2^n大小;hashtable默认是11,每次扩到2n+1大小
  • 线程安全:hashmap是线程不安全的,hashtable用syn锁整张表是线程安全的,但效率比较低
  • 存储:hashmap对null进行了特殊处理,key可以有一个为null,value可以为null;hashtable key和value都不能为null(value为null会报空指针)

33、HashMap是线程安全的吗?如果不是该如何解决?

  • HashMap不是线程安全的,多线程在put的时候可能会发生冲突
  • 线程安全的几种方式
    • hashtable:锁表,古老api不建议使用
    • Collections.synchronizedMap():锁表
    • ConcurrentHashMap:锁头节点,效率高
    • Lock,手动加锁

34、请你说说Java的四种引用方式

  • 强引用:任何时候都不会回收
  • 软引用:空间不够就回收
  • 弱引用:一旦发现就回收
  • 虚引用:任何时候都可能回收

35、请你讲下G1垃圾回收器

  • G1面向服务器的垃圾回收器,与CMS注重停顿时间不同,G1更注重cpu的吞吐量,所以适用于服务器的垃圾回收
  • 原理:三色标记+SATB(原始快照)
  • 特点
    • 并发与并行:可以并发的标记,又因为用在服务器中,可以用服务器中多核的优势做到并行运行,可以使用其中一个cpu进行gc其余进行运行
    • 可预测的停顿时间:G1将堆中物理的分区转换为逻辑上的分区,将region做为每次回收的最小单位,可以通过region计算出所需要的时间
    • 分代收集:G1不仅局限于某个分区,可以进行部分收集、混合收集
      • 过程:初始标记(STW)、并发标记、最终标记(STW)、筛选回收(STW)(按照成本、价值、停顿时间来回收)
    • 空间整合:整体是标记整理,局部是标记复制

36、请你说说内存溢出

  • 内存溢出:申请的内存大于系统能够提供的内存
  • 可能出问题的地方:除了线程虚拟机栈中的程序计数器,其他部分都可能会引发OOM
  • 排查方法
    • 思路
      • 查看jvm的参数是否正常
      • 分析堆的内存占用情况
      • 查看那个地方的gc除了问题
    • 过程
      • jps或者top或者ps -ef | grep java查进程id
      • jinfo pid:查看jvm的参数
      • jstat -gc pid:查看gc情况
      • jmap -heap pid:查看堆信息
      • jmap histo:live pid:查看存活的对象
      • jmap -F -dump:format=b,file=file.phrof pid:保存堆信息

37、请你说说内存泄漏

  • 不再使用的对象仍然被引用,导致垃圾收集器无法回收它们的内存,会进一步导致内存溢出(OOM)
  • 排查方式见内存溢出(看jvm参数、看堆信息、看gc信息)

38、请你说说String类,以及new和直接创建的区别

  • string类,提供了很多方法的api,重写了equals方法,本身类和数组是由final修饰的,所以不能改变
  • 直接创建的字符串是由字符串常量池管理的,通过new创建会先在字符串常量池中添加,再在堆中创建对象
  • 可以调用intern方法在字符串常量池中创建,如果有就返回

39、请你说说hashCode()和equals()的区别,为什么重写equals()就要重写hashcode()

  • hashcode()是获取对象的hash码,equals是判断对象是否相等
  • 当放入需要散列的集合类的时候,会优先比较hashcode,如果不等就说明对象不同,如果相等再根据equals进行判断

40、说说线程的创建方式

  • 继承Thread类重写start方法
  • 实现Runnable接口,重写run方法,并将对象作为Thread的参数
  • 实现Callable接口,重写call方法,并将对象作为FutureTask的参数

41、说说你对ArrayList的理解

  • 数据结构:数组
  • 扩容:初始为0,第一次插入时扩为10,每次扩1.5倍,用了System.arraycopy()拷贝新数组中

42、请你说说BIO、NIO、AIO

  • BIO:阻塞IO,线程io请求时会等待
  • NIO:非阻塞IO,和多路复用很像,一个线程监听多个请求
    • select,多路复用器,查看各个通道的状态
    • channel,通道,连接具体的实体(套接字)
    • buffer,缓存,存接受/发送的数据
  • AIO:异步IO

43、说说垃圾收集器

  • Serial、Serial Old、PawNew、CMS、Parallel Scavenge、Parallel Old、G1

44、请你说说Java的特点和优点,为什么要选择Java?

  • 特点
    • 面向对象
    • 简单易学,丰富的类库
    • 平台无关
    • 安全可靠,不直接操作内存管理内存空间
    • 多线程
  • 与c++的区别
    • 内存、继承、重载

45、介绍一下包装类的自动拆装箱与自动装箱

  • 自动装箱是指把一个基本类型的数据直接赋值给对应的包装类型;自动拆箱是指把一个包装类型的对象直接赋值给对应的基本类型;
  • 通过自动装箱、自动拆箱功能,可以大大简化基本类型变量和包装类对象之间的转换过程

46、说说wait()和sleep()的区别

  • 作用位置不同:sleep可以作用在任意位置,wait必须在同步代码块中
  • 唤醒条件不同:sleep会进入超时等待,一会自动唤醒,wait需要手动notify
  • 锁的处理不同:sleep不会释放锁,wait会释放锁
  • 所属的类型不同:sleep是Thread类,wait是object

47、说说你对线程池的理解

  • 作用:方便管理,减少开销,提高响应速度
  • 7大参数
    • 核心线程数:最小存活/同时运行的线程数
    • 最大线程数:当等待队列满了最大同时运行的线程数
    • 等待队列:阻塞队列,当达到核心线程数后加入队列
    • 存活时间:队列中的线程存活时间
    • 时间单位
    • 线程池创建方式:默认
    • 拒绝策略:
      • 直接丢弃
      • 抛出异常
      • 交给原线程
      • 丢弃等待队列中的第一个

48、简单说下你对JVM的了解

  • JDK:java开发工具包(包含jre、编译器javac和调试工具)——JRE:java运行时环境(包含jvm和类库)——jvm:java虚拟机(JIT编译器、解释器)
  • hotspot:openjdk、OracleJdk
  • jvm的内存模型:类的加载子系统、执行引擎、运行时的数据区

49、说说Java运行时数据区

  • 进程
    • 堆:
      • gc堆
      • 字符串常量池
      • 静态变量
    • 方法区:
      • 类元信息:类的基本信息,版本,方法
      • 运行时常量池:字面量、符号引用
      • JIT缓存
  • 线程
    • 程序计数器:用于线程上下文切换和命令的执行
    • 虚拟机栈:栈帧(动态链接、方法返回地址、操作数栈、局部变量表)
    • 本地方法栈
  • 直接内存:元空间、直接内存

50、请你讲下CMS垃圾回收器

  • 老年代垃圾回收器,与pawnew(新生代)一起工作,注重停顿时间(用户体验),标记清除
  • 原理:三色标记+增量更新
  • 过程
    • 初始标记 stw——并发标记——重新标记 stw——并发清除
  • 缺点
    • cpu敏感,和其他线程一起工作
    • 浮动垃圾,并发标记阶段产生的垃圾(多标问题)
    • 并发失败,浮动垃圾太多预留内存不够,stw启用serial old进行收集
    • 内存碎片

51、说说JVM的双亲委派模型

  • 原理:子类交给父加载器去加载
  • 作用:保证类不会被重复加载,保护java中自带类
  • 加载器:
    • BootstrapClassLoader:加载java的类 \lib
    • ExtensionClassLoader:拓展类的加载器 \lib\ext
    • AppClassLoader:用户的和第三方的类加载器

52、请你说说Java基本数据类型和引用类型

  • 8大基本数据类型
  • 引用数据类型存在堆中,基本数据类型存在栈中

53、请你说说Java的异常处理机制

  • 错误:OOM
  • 异常
    • 受检查的异常:可以捕获的异常(IO相关的错误)
    • 不受检查的异常(运行时异常):不可以捕获的异常(空指针异常、数组越界)

54、说说你对面向对象的理解

  • 特征:
    • 继承
    • 封装
    • 多态:父类指向子类实例,子类重写父类的方法
  • 类之间的关系
    • 依赖:一个类作为另一个的参数
    • 关联:一个类作为另一个的属性
      • 组合:总体消失分的也要消失
      • 聚合:总的消失分的还在
    • 继承
    • 实现

55、请介绍一下访问修饰符

  • 访问级别控制从小到大为: private->default->protected->public
    • private:类中被private修饰的成员只能在当前类的内部被访问
    • default:如果类中的成员或者一个外部类不使用任何访问修饰符来进行修饰,那么他就是default级别的,default访问控制的类成员或者外部类可以被相同包下的其他类访问
    • protected:类中被protected修饰的可以被当前类和当前类所在的包的其他类以及子类访问
    • public:这是Java中最宽松的访问级别,如果类成员被这个修饰符修饰,那么无论访问类和被访问类在不在一个包下,有没有父子关系,这个类成员都可以被访问到

56、说说Java中常用的锁及原理

  • 乐观锁:CAS(版本号)
  • 悲观锁:
    • Synchronized:ObjectMonitor
      • 等待队列、阻塞队列、锁升级、markword
    • Lock:AQS
      • 模板方法、FIFO的双线链表队列、volatile state

57、请你说说List与Set的区别

  • 集合类,是否可以重复
  • ArrayList、LinkedList
  • HashSet、TreeSet

58、请你讲一下Java NIO

  • Not Block IO/New IO,和Linux中的多路复用很像,通过多路复用器Select监听多个通道,当数据来时通过将数据读/写道缓冲区再执行进一步的操作
  • 组件
    • select:多路复用器,监听多个channel
    • channel:通道,连接具体的实体(文件描述符/socket)
    • buffer:缓冲区,存放读写的数据

59、说说GC的可达性分析

  • 判断对象是否可达有两种方式:引用计数法和可达性分析
  • 可达性分析:通过确定一个GC Roots,从root开始搜索将可以到达的对象加入引用链中,判断对象是否引用链中即是否可达
  • GC root
    • 虚拟机栈中引用的对象:局部变量、中间结果
    • 本地方法栈中引用的对象
    • 方法区常量引用的对象
    • 方法区静态变量引用的对象
  • 对象死亡(不可达一定被回收吗)
    • 第一次标记,判断对象不可达,进行筛选,如果没有覆盖finalize方法或者finalize方法已经被调用回收;或者加入队列,然后启动一个线程调用对象的finalize
    • 第二次标记,如果对象依旧不可达就回收,除非这个对象调用finalize方法时与引用链上的任何一个对象建立关联

60、类的实例化过程——对象的创建

  • 加载类信息:去方法区加载类的信息
  • 分配内存:堆上开辟空间
    • 分配方式
      • 空闲列表:找一个空的分配
      • 指针碰撞:先整理再分配
    • 并发
      • CAS+自旋
      • TLAB
  • 初始化零值
  • 设置对象头
  • 执行init方法

61、对象的内存布局

  • 对象头:
    • mark word:分代年龄、锁、hashcode
    • 类指针:class point
    • 数组长度(如果是数组的话)
  • 实例数据
  • 对齐填充

62、创建对象的方式

  • 使用 new 关键字调用对象的构造器;
  • 使用 Java 反射的 newInstance() 方法;
  • 使用 Object 类的 clone() 方法;
  • 使用对象流 ObjectInputStream的readObject()方法读取序列化对象;

Spring

1、说说你对MVC的理解

  • MVC是一种设计模式,在这种模式下软件被分为三层,即Model(模型)、View(视图)、Controller(控制器)
    • M:数据
    • V:视图/页面
    • C:控制,业务逻辑
  • 优点:采用分离的思想,降低了代码的耦合度,提高了代码的复用率
  • 缺点:增加了代码量
  • Spring MVC是spring框架中的一个模块,web模块提供了spring对MVC的实现

2、说说你对AOP的理解

  • 定义:AOP面向切面编程,是一种编程的思想,通过在编译时或者是运行时动态添加的方式,将一些重复的业务代码独立出来,减少代码的冗余
  • 方式
    • SpringAOP:运行期间通过动态代理的方式进行添加代码
      • JDK Proxy:通过实现接口(InvocationHeadle)的代理类实现
      • Cglib Proxy:通过继承/子类实例实现代理
    • AspectJ AOP:在编译期间动态织入

3、说说你对IoC的理解

  • IoC控制反转,是一种编程思想,用户将对象的创建和管理交给容器/框架来维护,DI依赖注入是实现IoC的一种方式,通过DI获取对象,不用手动维护对象之间依赖的关系,减少了代码的耦合
  • DI的几种方式
    • 属性注入(常用、不推荐)
    • set注入
    • 构造方法注入
  • springboot注解:@Autowired、@Resource

4、说说Spring Boot常用的注解

  • 注册为Bean:@Component、@Repository、@Service、@Controller、@Configure+@Bean
  • 依赖注入:@Autowired、@Resource
  • 自动装配:@Spring Boot Application
    • @SpringBootConfiguration、@ComponentScan、@EnableAutoConfiguration
      • @Import、@AutoConfigurationImportSelect——selectImport

5、说说Bean的生命周期

  • 生命周期

    • 扫描:将xml、注解中的对象封装成Bean Definition
    • class中包含的信息太少,还要包含一些类的信息、是否延迟加载、自动绑定模式
    • 注册:将BeanDefinition注册到BeanDefinitionMap中,key就是BeanDefinition的名字,value是BeanDefinition
    • 获取:BeanFactory的doGetBean()方法,如果没有就开始下面的过程
    • 实例化:
      • 前置函数postProcess函数
      • 执行doCreateBean方法,创建Bean的实例,加入三级缓存
      • 后置函数
    • 依赖注入/属性填充
      • 循环依赖问题——三级缓存
        • singletonObjects——earlySingletonObjects——singletonFactory
        • a依赖b,b依赖a,实例化a注入b时先创建b,b在依赖注入时从3级缓存中找到a,放入2级缓存,完成b后,a再进行依赖注入,初始化完成将2级缓存删了放1级缓存中
        • 为什么2级缓存不行
          • 因为当有代理出现时,b放的是代理对象,a在初始化完成后查看有无代理对象,有的话就直接用代理对象,否则再创建代理对象放1级
          • 如果去掉3级缓存,a在实例化后需要将代理对象放入2级缓存
          • 如果去掉2级缓存,b、c都依赖a,但会依赖不同的代理对象
    • 初始化
      • 是否实现了aware方法
      • 前置函数
      • 是否有自定义的初始化方法
      • 后置函数:产生代理对象放入1级缓存
    • 销毁
      • 是否有自定义的destroy方法
      • DisposableBean的destroy方法
  • 作用域

    • singleton
    • prototype
    • session
    • request
    • globalsession

6、简单介绍Spring

  • spring是一种轻量级的java开发框架,其中包括很多模块(web模块、data模块、core模块、Aop模块、test模块)
  • 特点:AOP、IoC

7、介绍一下MyBatis的缓存机制

  • 生命周期
    • sqlsessionFactory:全局唯一
    • sqlSession:每个语句
  • 一级缓存(默认开启)会将查询的结果存入sqlSession缓存中,当遇到更新/删除操作的时候就清除缓存,当sqlSession会话关闭时存入二级缓存(手动开启)中(sqlSessionFactory)
  • 先查二级缓存,再查一级,再查数据库
  • 过期用lru

8、说说你对Spring Boot的理解,以及它和Spring的区别?

  • springboot是对spring的简化,通过约定大于配置的思想简化了spring中的很多配置
    • 优点
      • 快速构建项目
      • 无需配置继承框架
      • 独立运行不需要serlvet容器(tomcat)
      • 提供实时监控
    • 核心功能
      • 自动化配置:很多spring配置不用自己来了
      • 起步依赖:特殊的maven(spring-boot-starter-XXX),将依赖功能聚合
      • 端点监控:可以监控程序运行

9、说说Spring Boot的自动装配

  • SpringBootApplication注解含以下3个注解:
    • ComponentScan,扫描包下所有的bean并加载
    • SpringBootConfiguration:原配置类,相当于@Configuration
    • EnableAutoConfiguration:通过@import的方式导入了@AutoConfigurationImportSelect类,并调用selectImports方法,从META-INF路径下的spring.factories中 加载spring.factories中的AutoConfiguration 类,满足@conditional注解条件时,就实例化该AutoConfiguration类中定义的组件bean,并再次根据扫描到bean中的import方法进行加载,最终完成自动装配。

10、说说@Autowired和@Resource注解的区别

  • @Autowired是Spring提供的注解,@Resource是JDK提供的注解
  • @Autowired是只能按类型注入,@Resource默认按名称注入,也支持按类型注入
  • @Autowired也可以通过@Qualifier指定名称
  • @Resource有两个中重要的属性:name和type
    • 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
    • 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
    • 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
    • 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;

11、说说Spring Boot的启动流程

  • run方法:获取监听器参数配置-》打印banner-》创建并初始化容器-》监听发送通知

12、介绍一下Spring MVC的执行流程

  • https://blog.csdn.net/qq_39543984/article/details/111132789

img

  • 1、用户点击某个请求路径,发起一个 HTTP request 请求,该请求会被提交到 DispatcherServlet(前端控制器);
  • 2、由 DispatcherServlet 请求一个或多个 HandlerMapping(处理器映射器),并返回一个执行链(HandlerExecutionChain)。
  • 3、DispatcherServlet 将执行链返回的 Handler 信息发送给 HandlerAdapter(处理器适配器);
  • 4、HandlerAdapter 根据 Handler 信息找到并执行相应的 Handler(常称为 Controller);
  • 5、Handler 执行完毕后会返回给 HandlerAdapter 一个 ModelAndView 对象(Spring MVC的底层对象,包括 Model 数据模型和 View 视图信息);
  • 6、HandlerAdapter 接收到 ModelAndView 对象后,将其返回给 DispatcherServlet ;
  • 7、DispatcherServlet 接收到 ModelAndView 对象后,会请求 ViewResolver(视图解析器)对视图进行解析;
  • 8、ViewResolver 根据 View 信息匹配到相应的视图结果,并返回给 DispatcherServlet;
  • 9、DispatcherServlet 接收到具体的 View 视图后,进行视图渲染,将 Model 中的模型数据填充到 View 视图中的 request 域,生成最终的 View(视图);
  • 10、视图负责将结果显示到浏览器(客户端)。
  • 记忆:请求——前端控制器——映射器(找handler执行链)——适配器(执行handle/controller)——视图解析器(解析视图)——填充渲染

13、在MyBatis中$和#有什么区别

  • #{}相当于使用PreparedStatement ,会将sql中的特殊字符进行转义;${}是字符串替换,有sql注入的风险

14、说说Spring Boot的起步依赖

  • 约定大于配置的思想,springboot将各种场景下的依赖做成starter,用户只需要在maven中引入starter依赖springboot就可以自动的扫描加载信息并启动默认的配置。

15、说说Spring事务管理

  • 编程式事务:TransactionTemplate,可以将事务管理的范围控制的更为精确
  • 声明式事务:@Transactional
    • 作用范围:方法、类(所有方法都开启)、接口(不建议)
    • 参数:事务的传播级别、事务的隔离级别等

16、说说Bean的作用域,以及默认的作用域

  • singleton :在Spring容器中仅存在一个实例,即Bean以单例的形式存在
  • prototype :每次调用getBean()时,都会执行new操作,返回一个新的实例
  • request :每次HTTP请求都会创建一个新的Bean
  • session :同一个HTTP Session共享一个Bean,不同的HTTP Session使用不同的Bean
  • globalSession:同一个全局的Session共享一个Bean,一般用于Portlet环境

17、说说BeanFactory和FactoryBean的区别

  • Bean Factory是一个IoC容器用来产生Bean
  • FactoryBean是一个Bean对象,可以产生或者修饰bean

18、BeanFactory和ApplicationContext

  • 相同点:都是IoC容器
  • 不同点
    • 功能:ApplicationContext是BeanFactory的子类,具有BeanFactory的功能外还有一些附加的功能,例如国际化什么的
    • 加载方式:BeanFactory是延迟加载,需要的时候才加载,ApplicationContext是开始时全部加载
    • 创建方式:BeanFactory是编程创建,ApplicationContext是声明创建
    • (BeanPostProcessor)注册方式:BeanFactory手动,ApplicationContext自动注册
  • 所以更建议用ApplicationContext
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值