您当前的位置: 首页 > 技术文章 > 前端开发

个人面试汇总

作者: 时间:2022-05-10阅读数:人阅读

IOC容器里面是如何创造对象的

在配置文件被加载的时候,我们的spring容器中管理的bean就已经被初始化了。

在getBean的时候,这个类的对象就已经被创建了,使用的就是无参构造方法创建对象的。

IOC也可以用有参构造器来创建对象

1、用下标的方式来通过有参构造器创建对象:
在这里插入图片描述
可以看到上述下标为0的参数,是不是就只有一个啊,就是有参构造中的name参数
在这里插入图片描述
2、用参数的类型的方式来通过有参构造器创建对象:
在这里插入图片描述
3、直接通过参数的名称的方式来通过有参构造器创建对象
在这里插入图片描述
以上就是spring容器的IOC理念,创建对象的所有方式,一种默认的无参构造器创建,3种有参构造器的创建方式

Spring AOP的实现

Spring AOP机制是由代理模式实现的。
代理模式分为静态代理和动态代理。

静态代理

AspectJ(编译时增强)使用的是静态代理。静态代理指的是AOP框架在编译阶段生成AOP的代理类,它会在编译阶段将AspectJ移植到java字节码中,运行的时候就是增强后的AOP对象。
AspectJ实现方式上是依赖于特殊的AJC编译器。它并非是Spring AOP框架的一部分,而是Spring AOP框架使用了Aspect的Annotation(注解),用来定义切面、切点等功能。
在这里插入图片描述

角色分析

抽象角色:一般使用接口或者抽象类解决
真实角色:被代理的角色
代理角色:用来代理真实角色的。代理真实角色后一般会做一些附属操作
客户:调用代理对象的人

动态代理

动态代理的底层其实就是反射机制

  • 动态代理角色和静态代理一样
  • 动态代理的代理类是动态生成的,不是自己直接写好的
  • 动态代理分为两类:基于接口的动态代理(JDK动态代理),基于类的动态代理(CGLIB动态代理)
自动生成代理类通用结构

核心:实现InvocationHandler接口,使用Proxy.newProxyInstance()方法生成代理类
在这里插入图片描述

调用上述方法实现动态代理

在这里插入图片描述

SpringAOP使用的是动态代理。所谓动态代理指的是AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象就包含了目标对象的所有方法,并且在特定的切点做了增强处理,并回调原对象的方法。底层采用的是JDK/CGLIB动态代理。

Spring AOP里面的几个名词的概念

1)连接点(Join point):指程序运行过程中所执行的方法。在Spring AOP中,一个连接点总代表一个方法的执行。

2)切面(Aspect):被抽取出来的公共模块,可以用来会横切多个对象。Aspect切面可以看成 Pointcut切点 和 Advice通知 的结合,一个切面可以由多个切点和通知组成。

3)切点(Pointcut):切点用于定义 要对哪些Join point进行拦截。

4)通知(Advice):指要在连接点(Join Point)上执行的动作,即增强的逻辑,比如权限校验和、日志记录等。通知有各种类型,包括Around、Before、After、After returning、After throwing。

5)目标对象(Target):包含连接点的对象,也称作被通知(Advice)的对象。 由于Spring AOP是通过动态代理实现的,所以这个对象永远是一个代理对象。

6)织入(Weaving):通过动态代理,在目标对象(Target)的方法(即连接点Join point)中执行增强逻辑(Advice)的过程。

7)引入(Introduction):添加额外的方法或者字段到被通知的类。Spring允许引入新的接口(以及对应的实现)到任何被代理的对象。例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。

Spring容器的启动流程

1、初始化Spring容器,注册内置的BeanPostProcessor的BeanDefinition到容器中
2、将配置类的BeanDefinition注册到容器中
3、调用refresh()方法刷新容器
初始化:
spring容器的初始化时,通过this()调用了无参构造函数,主要做了以下三个事情:
(1)实例化BeanFactory【DefaultListableBeanFactory】工厂,用于生成Bean对象
(2)实例化BeanDefinitionReader注解配置读取器,用于对特定注解(如@Service、@Repository)的类进行读取转化成 BeanDefinition 对象,(BeanDefinition 是 Spring 中极其重要的一个概念,它存储了 bean 对象的所有特征信息,如是否单例,是否懒加载,factoryBeanName 等)
(3)实例化ClassPathBeanDefinitionScanner路径扫描器,用于对指定的包目录进行扫描查找 bean 对象

Spring框架中的Bean是线程安全的么?如果线程不安全,那么如何处理?

Spring容器本身并没有提供Bean的线程安全策略,因此可以说Spring容器中的Bean本身不具备线程安全的特性,但是具体情况还是要结合Bean的作用域来讨论。

(1)对于prototype作用域的Bean,每次都创建一个新对象,也就是线程之间不存在Bean共享,因此不会有线程安全问题。

(2)对于singleton作用域的Bean,所有的线程都共享一个单例实例的Bean,因此是存在线程安全问题的。但是如果单例Bean是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。比如Controller类、Service类和Dao等,这些Bean大多是无状态的,只关注于方法本身。

解决办法

1、作用域由“singleton”改为“prototype”。

2、采用ThreadLocal解决线程安全问题,为每个线程提供一个独立的变量副本,不同线程只操作自己线程的副本变量。

  • ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。

索引的数据结构

二叉树

二叉树(binary tree)是指树中节点的度不大于 2 的有序树,它是一种最简单且最重要的树。二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树
在这里插入图片描述

特点:
1、父节点下面有两个子节点。
2、右边节点的数据大于左边节点的数据。

红黑树

红黑树是一种特定类型的二叉树,它的左右子树高差有可能大于 1。
在这里插入图片描述
特点:
1、根节点必须是黑色的
2、红色节点不可连续,黑色节点可连续
3、对于每个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点
插入步骤:
1、搜索
2、创建新节点,插入合适位置
3、调整结构或调整颜色
AVL根据每个节点平衡因子来决定是否进行结构调整,而红黑树通过节点颜色限制来进行结构和颜色调整。

B-Tree

1、叶子结点具有相同的深度,叶节点的指针为空
2、所有元素不重复
3、节点中的数据索引从左到右边递增排列
在这里插入图片描述其中每个节点中存放当前节点包含的键值(Key/Data)和指向下一个节点的指针。

查找:
例如,如果我们在上述B树中搜索数据49。该过程将如下所示:
1、将项目49与根节点78进行比较。由于49 <78,因此移至其左子树。
2、从40 <49 <56开始,遍历40的右子树。
3、49> 45,向右移动。比较49。
4、找到匹配项,返回。
插入:
1、遍历B树,以找到可以在其上插入节点的适当叶节点。
2、如果叶节点包含少于m-1个键,则按升序插入元素。
3、如果叶子节点包含m-1个键,则请执行以下步骤

  • 按元素的升序插入新元素。
  • 将节点拆分为中间的两个节点。
  • 将中值元素推到其父节点。

B+Tree

1、非叶子结点不存储数据,只存储索引(冗余),可以存放更多的索引
2、叶子结点包含所有索引字段
3、叶子结点用指针链接,提高区间访问的性能(可以提升范围查找的效率)

Hash

1、对索引的 key 进行一次 hash 计算就可以定位出数据存储的位置
2、很多的时候 hash 索引要比 B+ 树索引更高效
3、仅能满足 “=” , “in” 不支持范围查询

创建索引的方式

1)使用 CREATE INDEX 语句

可以使用专门用于创建索引的 CREATE INDEX 语句在一个已有的表上创建索引,但该语句不能创建主键。

语句格式:CREATE <索引名> ON <表名> (<列名> [<长度>] [ ASC | DESC])

2使用 CREATE TABLE 语句

索引也可以在创建表(CREATE TABLE)的同时创建。

类的加载顺序、类加载器

主要包含加载、验证、准备、解析、初始化、使用、卸载七个方面
一、加载

在加载阶段,虚拟机主要完成三件事:

1.通过一个类的全限定名来获取定义此类的二进制字节流。

2.将这个字节流所代表的静态存储结构转化为方法区域的运行时数据结构。

3.在Java堆中生成一个代表这个类的java.lang.Class对象,作为方法区域数据的访问入口

二、验证

验证阶段作用是保证Class文件的字节流包含的信息符合JVM规范,不会给JVM造成危害。如果验证失败,就会抛出一个java.lang.VerifyError异常或其子类异常。验证过程分为四个阶段:

1.文件格式验证:验证字节流文件是否符合Class文件格式的规范,并且能被当前虚拟机正确的处理。

2.元数据验证:是对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言的规范。

3.字节码验证:主要是进行数据流和控制流的分析,保证被校验类的方法在运行时不会危害虚拟机。

4.符号引用验证:符号引用验证发生在虚拟机将符号引用转化为直接引用的时候,这个转化动作将在解析阶段中发生。

三、准备

准备阶段为变量分配内存并设置类变量的初始化。在这个阶段分配的仅为类的变量(static修饰的变量),而不包括类的实例变量。对已非final的变量,JVM会将其设置成“零值”,而不是其赋值语句的值:

pirvate static int size = 12;

那么在这个阶段,size的值为0,而不是12。 final修饰的类变量将会赋值成真实的值。

四、解析

解析过程是将常量池内的符号引用替换成直接引用。主要包括四种类型引用的解析。类或接口的解析、字段解析、方法解析、接口方法解析。

五、初始化

在准备阶段,类变量已经经过一次初始化了,在这个阶段,则是根据程序员通过程序制定的计划去初始化类的变量和其他资源。这些资源有static{}块,构造函数,父类的初始化等。

至于使用和卸载阶段阶段,这里不再过多说明,使用过程就是根据程序定义的行为执行,卸载由GC完成。

类加载器

1、Bootstrap Classloader : 启动类加载器,用来加载 %JAVA_HOME%/jre/lib 下的, 如 rt.jar中的class文件 或者 xbootclasspath选项指定的jar包

2、Extension Classloader : 扩展类加载器 , 用来加载 %JAVA_HOME%/jre/ext 中的class文件 或者 -Djava.ext.dirs指定目录下的jar包

3、 Application Classloader : 应用类加载器 , 用来加载classpath下的class文件

4、Custom Classloader : 用户自定义类加载器,用来加载自定义内容.此加载器需要用户自己继承Classloader类

synchronized

1.Synchronized修饰非静态方法,实际上是对调用该方法的对象加锁,俗称“对象锁”。
2.Synchronized修饰静态方法,实际上是对该类对象加锁,俗称“类锁”。
3.对于类锁synchronized static,是通过该类直接调用加类锁的方法,而对象锁是创建对象调用加对象锁的方法,两者访问是不冲突的,对于同一类型锁锁住的方法,同一对象是无法同时访问的.

currenthashmap集合

主要就是为了应对hashmap在并发环境下不安全而诞生的,ConcurrentHashMap的设计与实现非常精巧,大量的利用了volatile,final,CAS等lock-free技术来减少锁竞争对于性能的影响。

本站所有文章、数据、图片均来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:licqi@yunshuaiweb.com

加载中~
如果您对我们的成果表示认同并且觉得对你有所帮助可以给我们捐赠。您的帮助是对我们最大的支持和动力!
捐赠我们
扫码支持 扫码支持
扫码捐赠,你说多少就多少
2
5
10
20
50
自定义
您当前余额:元
支付宝
微信
余额

打开支付宝扫一扫,即可进行扫码捐赠哦

打开微信扫一扫,即可进行扫码捐赠哦

打开QQ钱包扫一扫,即可进行扫码捐赠哦