面试题整理

Spring 的 AOP 和 IOC?

AOP(Aspect-Oriented Programming), 即 面向切面编程, 它与 OOP( Object-Oriented Programming, 面向对象编程) 相辅相成, 提供了与 OOP 不同的抽象软件结构的视角. 在 OOP 中, 我们以类(class)作为我们的基本单元, 而 AOP 中的基本单元是 Aspect(切面)。

IOC 就是控制反转。Spring 框架的核心是 Spring 容器。容器创建对象,将它们装配在一起,配置它们并管理它们的完整生命周期。Spring 容器使用依赖注入来管理组成应用程序的组件。容器通过读取提供的配置元数据来接收对象进行实例化,配置和组装的指令。该元数据可以通过 XML,Java 注解或 Java 代码提供。

AOP 有哪些实现方式?

实现 AOP 的技术,主要分为两大类:

  • 静态代理 - 指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强;
    • 编译时编织(特殊编译器实现)
    • 类加载时编织(特殊的类加载器实现)。
  • 动态代理 - 在运行时在内存中“临时”生成 AOP 动态代理类,因此也被称为运行时增强。
    • JDK 动态代理:通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口 。JDK 动态代理的核心是 InvocationHandler 接口和 Proxy 类 。
    • CGLIB动态代理: 如果目标类没有实现接口,那么 Spring AOP 会选择使用 CGLIB 来动态代理目标类 。CGLIB ( Code Generation Library ),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意, CGLIB 是通过继承的方式做的动态代理,因此如果某个类被标记为 final ,那么它是无法使用 CGLIB 做动态代理的。

Spring AOP 和 AspectJ AOP 有什么区别?

Spring AOP是属于运行时增强,而AspectJ是编译时增强。Spring AOP基于代理 (Proxying),而AspectJ基于字节码操作(Bytecode Manipulation)。

Spring AOP已经集成了AspectJ,AspectJ应该算得上是Java生态系统中最完整的AOP框架 了。AspectJ相比于Spring AOP功能更加强大,但是Spring AOP相对来说更简单。

如果我们的切面比较少,那么两者性能差异不大。但是,当切面太多的话,最好选择 AspectJ,它比SpringAOP快很多。

IOC 如何解决循环依赖?

最后来描述下就上面那个循环依赖 Spring 解决的过程(A为person,B为car,C为money):首先 A 完成初始化第一步并将自己提前曝光出来(通过 ObjectFactory 将自己提前曝光),在初始化的时候,发现自己依赖对象 B,此时就会去尝试 get(B),这个时候发现 B 还没有被创建出来,然后 B 就走创建流程,在 B 初始化的时候,同样发现自己依赖 C,C 也没有被创建出来,这个时候 C 又开始初始化进程,但是在初始化的过程中发现自己依赖 A,于是尝试 get(A),这个时候由于 A 已经添加至缓存中(一般都是添加至三级缓存 singletonFactories ),通过 ObjectFactory 提前曝光,所以可以通过 ObjectFactory.getObject() 拿到 A 对象,C 拿到 A 对象后顺利完成初始化,然后将自己添加到一级缓存中,回到 B ,B 也可以拿到 C 对象,完成初始化,A 可以顺利拿到 B 完成初始化。到这里整个链路就已经完成了初始化过程了。

了解 fastJson 吗?区别是什么?用到了什么?

Fastjson是一个Java语言编写的高性能功能完善的JSON库。它采用一种“假定有序快速匹配”的算法,把JSON Parse的性能提升到极致,是目前Java语言中最快的JSON库。Fastjson接口简单易用,已经被广泛使用在缓存序列化、协议交互、Web输出、Android客户端等多种应用场景。

fastjson 的兼容性比 jackson 要差一些。

前后端分离如何约束参数?

前端通过Ajax请求来访问后端的数据接口,将Model展示到View中即可。

前后端开发者只需要提前约定好接口文档(URL、参数、数据类型.….),然后分别独立开发即可,前端可以造假数据进行测试,完全不需要依赖于后端,最后完成前后端集成即可,真正实现了前后端应用的解耦合,极大地提升了开发效率。

MVVM 是什么?

Model View View-Model.

把Model和View关联起来的就是ViewModel。ViewModel负责把Model的数据同步到View显示出来,还负责把View的修改同步回Model。

如何设计接口?

单一职责。

开放封闭原则。对扩展开放,对修改封闭。

里氏替换原则。子类型可以替换掉父类型。

依赖倒置原则。抽象不应该依赖于细节。细节应该依赖抽象。

https://zhuanlan.zhihu.com/p/193058932

接口的安全性设计?基于序列化?

总的就是说安全性问题,假如没有一个接口(即没有Serializable来标记是否可以序列化),让所有对象都可以序列化。那么所有对象通过序列化存储到硬盘上后,都可以在序列化得到的文件中看到属性对应的值(后面将会通过代码展示)。所以最后为了安全性(即不让一些对象中私有属性的值被外露),不能让所有对象都可以序列化。要让用户自己来选择是否可以序列化,因此需要一个接口来标记该类是否可序列化。

对于集合类的了解?

Java 集合类主要是由两个根接口 Collection 和 Map 派生出来的。

Collection 派生出了三个子接口:List、Set、Queue(Java5新增的队列),因此Java集合大致可以分为 List、Set、Queue四种接口体系。

注意:Collections 是一个工具类。

讲一下 ArrayList?

不保证线程安全。

ArrayList 只能包含对象类型。

ArrayList 的底层使用了数组。

ArrayList 可以动态扩容。

ArrayList 扩容的本质就是计算出新的扩容数组的 size 后进行实例化,并将原有数组内容复制到新数组中去。默认情况下,新的容量会是原容量的 1.5 倍。

ArrayList 和 Vector 的区别?

  • Vector 是线程安全的。
  • ArrayList 是线程不安全的。

讲下 HashMap?

jdk1.8 中,由“数组+链表+红黑树”组成。

hash冲突时,会链表处理。

  • 当链表超过8且数据总量超过64时才会转红黑树。
  • 将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换成红黑树,以减少搜索时间。

为什么不直接用红黑树?

因为红黑树要进行左旋、右旋、变色这些操作来保持平衡,而单链表不需要。

当元素小于 8 个的时候,此时做查询操作,链表结构已经能够保证查询性能。当元素大于8个的时候,红黑树搜索时间复杂度是O(logN),而链表是O(N),此时需要红黑树来加快查询速度。但是新增节点的效率变慢了。

因此,如果一开始就用红黑树结构,元素太少,新增效率又比较慢,无疑这是浪费性能的。

不用红黑树,用二叉查找树可以吗?

可以。但是二叉查找树在特殊情况下会变成一条线性结构。

为什么链表改为红黑树的阈值是8?

因为泊松分布。

lambda 表达式用过吗?举个例子:for 循环和 foreach 的区别?

Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。

Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。

使用 Lambda 表达式可以使代码变的更加简洁紧凑。

for 循环和 foreach 的区别:

一、区别

  • 1)for循环是基于下标(偏移量)来定位的循环。
  • 2)foreach是基于指针直接移动(地址运算)的循环。
  • 3)foreach与for循环的明显差别在于foreach循环时循环对象(数组、集合)被锁定,不能对循环对象中的内容进行增删改操作

二、两者效率比较
对于通过下标访问的数据结构。例如数组,ArrayList 使用下标访问的for循环效率本身就很高。所以foreach这种指针直接移动的效率可能甚至不如通过下标访问,但差别不会太大,但对于链式结构LinkedList,for基于下标访问会每次从头查询,最好不要使用for。foreach循环使用指针直接偏移的高效的地址运算,效率会高非常多,差距也很大。链表循环超过10万次for循环可能会直接卡死,而foreach仍然只需要几毫秒。

数据库的设计应该遵循什么原则?

一致性原则。

完整性原则。

安全性原则。

可伸缩性与可扩展性。

规范性原则。

volatile

只能保证可见性。

不能保证原子性。


面试题整理
http://fanlumaster.github.io/2022/03/19/面试题整理/
作者
fanlumaster
发布于
2022年3月19日
许可协议