一、HashMap 和 Hashtable 有什么区别?
- HashMap是线程不安全的,HashTable是线程安全的;
- HashMap中允许键和值为null,HashTable不允许;
- HashMap的默认容器是16,为2倍扩容,HashTable默认是11,为2倍+1扩容;
二、JVM 对 Java 的原生锁做了哪些优化?
1、自旋锁
在线程进行阻塞的时候,先让线程自旋等待一段时间,可能这段时间其它线程已经解锁,这时就无需让线程再进行阻塞操作了。
自旋默认次数是10次。
2、自适应自旋锁
自旋锁的升级,自旋的次数不再固定,由前一次自旋次数和锁的拥有者的状态决定。
3、锁消除
在动态编译同步代码块的时候,JIT编译器借助逃逸分析技术来判断锁对象是否只被一个线程访问,而没有其他线程,这时就可以取消锁了。
4、锁粗化
当JIT编译器发现一系列的操作都对同一个对象反复加锁解锁,甚至加锁操作出现在循环中,此时会将加锁同步的范围粗化到整个操作系列的外部。
锁粒度:不要锁住一些无关的代码。
锁粗化:可以一次性执行完的不要多次加锁执行。
三、为什么说 Synchronized 是非公平锁?
当锁被释放后,任何一个线程都有机会竞争得到锁,这样做的目的是提高效率,但缺点是可能产生线程饥饿现象。
四、jsp 有哪些内置对象?作用分别是什么?
JSP九大内置对象:
- pageContext,页面上下文对象,相当于页面中所有功能的集合,通过它可以获取JSP页面的out、request、response、session、application对象。
- request
- response
- session
- application,应用程序对象,application实现了用户间数据的共享,可存放全局变量,它开始于服务器启动,知道服务器关闭。
- page,就是JSP本身。
- exception
- out,out用于在web浏览器内输出信息,并且管理应用服务器上的输出缓冲区,作用域page。
- config,取得服务器的配置信息。
五、http 响应码 301 和 302 代表的是什么?有什么区别?
301和302状态码都表示重定向,当浏览器拿到服务器返回的这个状态码后悔自动跳转到一个新的URL地址。
301代表永久性重定向,旧地址被永久移除,客户端向新地址发送请求。
302代表暂时性重定向,旧地址还在,客户端继续向旧地址发送请求。
303代表暂时性重定向,重定向到新地址时,必须使用GET方法请求新地址。
307代表暂时性重定向,与302的区别在于307不允许从POST改为GET。
307代表永久性重定向,与301的区别在于308不允许从POST改为GET。
六、什么是设计模式?你是否在你的代码里面使用过任何设计模式?
1、什么是设计模式?
设计模式是解决软件开发某些特定问题而提出的一些解决方案,也可以理解为解决问题的一些固定思路。
通过设计模式可以帮助我们增强代码的可复用性、可扩展性、灵活性。
我们使用设计模式的最终目的是实现代码的高内聚、低耦合。
2、设计模式的七大原则
- 单一职责原则
- 接口隔离原则
- 依赖倒转原则
- 里式替换原则
- 开闭原则
- 迪米特法则
- 合成复用原则
3、你是否在你的代码里面使用过任何设计模式?
(1)单例模式
JDK种的runtime,Spring种的singeton。
(2)简单工厂模式
Spring的BeanFactory,根据传入一个唯一标识来获得bean对象。
(3)原型模式
clone()
(4)代理模式
Spring的AOP中,Spring实现AOP功能的原理就是代理模式,①JDK动态代理。②CGLIB动态代理,使用Advice(通知)对类进行方法级别的切面增强。
(5)装饰器模式
为类添加新的功能,防止类爆炸;
IO流、数据源包装,Spring中用到的装饰器模式表现在Wrapper。
七、什么是控制反转(IOC)?什么是依赖注入?
借助Spring实现具有依赖关系的对象之间的解耦。
对象A运行需要对象B,由主动创建变为IOC容器注入,这便是控制反转。
获得依赖对象的过程被反转了,获取依赖对象的过程由自身创建变为由IOC容器注入,这便是依赖注入。
八、BeanFactory 和 ApplicationContext 有什么区别?
1、BeanFactory是Spring的最底层接口,包含bean的定义,管理bean的加载,实例化,控制bean的生命周期,特点是每次获取对象时才会创建对象。
ApplicationContext是BeanFactory的子接口,拥有BeanFactory的全部功能,并且扩展了很多高级特性,每次容器启动时就会创建所有的对象。
ApplicationContext的额外功能:
- 继承MessageSource,支持国际化;
- 统一的资源文件访问方式;
- 提供在监听器中注册bean;
- 同时加载过个配置文件;
- 载入多个(有继承关系)上下文,使得每个上下文都专注于一个特定的层次,比如应用的web层;
2、BeanFactory通常以编程的方式被创建,ApplicationContext可以以声明的方式创建,如使用ContextLoader。
3、BeanFactory 和 ApplicationContext都支持BeanPostProcessor,BeanFactoryPostProcessor,但BeanFactory需要手动注册,ApplicationContext则是自动注册。
九、什么是 JavaConfig?
JavaConfig是Spring3.0新增的概念,就是以注解的形式取代Spring中繁琐的xml文件。
JavaConfig结合了xml的解耦和java编译时检查的优点。
@Configuration,表示这个类是配置类;
@ComponentScan,相当于xml的<context:componentScan basepackage=>;
@Bean,相当于xml的<bean id="student" class="com.guor.entity">;
@EnableWebMvc,相当于xml的<mvc:annotation-driven>;
@ImportResource,相当于xml的<import resource="application-context-cache.xml">;
@PropertySource,用于读取properties配置文件;
@Profile,一般用于多环境配置,激活时可用@ActiveProfile("dev")注解;
十、什么是 ORM 框架?
ORM(Object-relational mapping),对象关系映射。
是为了解决面向对象与关系型数据库存在的不匹配问题。
ORM框架的优点:
- 开发效率更高
- 数据访问更抽象、轻便
- 支持面向对象封装
十一、mybatis 是否支持延迟加载?延迟加载的原理是什么?
1、mybatis 是否支持延迟加载?
延迟加载其实就是讲数据加载时机推迟,比如推迟嵌套查询的时机。
延迟加载可以实现先查询主表,按需实时做关联查询,返回关联表结果集,一定程度上提高了效率。
mybatis仅支持关联对象association和关联集合对象collection的延迟加载,association是一对一,collection是一对多查询,在mybatis配置文件中可以配置lazyloadingEnable=true/false。
2、延迟加载的原理是什么?
使用CGLIB为目标对象建立代理对象,当调用目标对象的方法时进入拦截器方法。
比如调用a.getB().getName(),拦截器方法invoke()发现a.getB()为null,会单独发送事先准备好的查询关联B对象的sql语句,把B查询出来然后调用a.setB(b),也是a的对象的属性b就有值了,然后调用getName(),这就是延迟加载的原理。
十二、RabbitMQ有哪些重要的角色?有哪些重要的组件?
1、RabbitMQ有哪些重要的角色?
客户端、RabbitMQ、服务端。
2、有哪些重要的组件?
(1)connectionFactory(连接管理器)
应用程序与RabbitMQ之间建立连接的管理器。
(2)Channel(信道)
消息推送使用的信道。
(3)RoutingKey(路由键)
用于把生产者的数据分配到交换机上。
(4)Exchange(交换机)
用于接受和分配消息。
(5)BindKey(绑定键)
用于把交换机的消息绑定到队列上
(6)Queue(队列)
用于存储生产者消息。
十三、一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 mysql 数据库,又插入了一条数据,此时 id 是几?
一般情况下,我们创建的表类型是InnoDB。
- 不重启MySQL,如果新增一条记录,id是8;
- 重启,ID是6;因为InnoDB表只把自增主键的最大ID记录在内存中,如果重启,已删除的最大ID会丢失。
如果表类型是MyISAM,重启之后,最大ID也不会丢失,ID是8;
InnoDB必须有主键(建议使用自增主键,不用UUID,自增主键索引查询效率高)、支持外键、支持事务、支持行级锁。
系统崩溃后,MyISAM很难恢复;
综合考虑,优先选择InnoDB,MySQL默认也是InnoDB。
十四、Redis有哪些功能?
1、服务端的数据缓存
专门部署一个Redis的服务器;
2、持久化
Redis持久化指的是Redis会把内存中的数据写到磁盘中,在Redis重启时先加载这些数据,就觉Redis服务器重启导致的内存丢失问题。
3、哨兵(Sentinel)和复制
Sentinel可以管理多个Redis服务器,它提供了监控、提醒以及自动的故障转移功能;
复制则是让Redis服务器可以配备备份的服务器;
Redis也是通过这两个功能保证Redis的高可用;
4、集群(Cluster)
单台服务器资源总是有上限的,CPU和IO资源可以通过主从复制,进行读写分离,把一部分CPU和IO的压力转移到从服务器上,但是内存资源怎么办,主从模式只是数据的备份,并不能扩充内存;
现在我们可以横向扩展,让每台服务器只负责一部分任务,然后将这些服务器构成一个整体,对外界来说,这一组服务器就像是集群一样。
十五、什么是类加载器,类加载器有哪些?
1、什么是类加载器?
类加载器负责加载所有的类,其为所有被载入内存的类生成一个java.lang.Class实例对象。
2、类加载器有哪些?
JVM有三种类加载器:
(1)启动类加载器
该类没有父加载器,用来加载Java的核心类,启动类加载器的实现依赖于底层操作系统,属于虚拟机实现的一部分,它并不继承自java.lang.classLoader。
(2)扩展类加载器
它的父类为启动类加载器,扩展类加载器是纯java类,是ClassLoader类的子类,负责加载JRE的扩展目录。
(3)应用程序类加载器
它的父类为扩展类加载器,它从环境变量classpath或者系统属性java.lang.path所指定的目录中加载类,它是自定义的类加载器的父加载器。
十六、说一下类加载的执行过程?
当程序主动使用某个类时,如果该类还未被加载到内存中,JVM会通过加载、连接、初始化3个步骤对该类进行类加载。
1、加载
加载指的是将类的class文件读入到内存中,并为之创建一个java.lang.Class对象。
类的加载由类加载器完成,类加载器由JVM提供,开发者也可以通过继承ClassLoader基类来创建自己的类加载器。
通过使用不同的类加载器可以从不同来源加载类的二进制数据,通常有如下几种来源:
- 从本地文件系统加载
- 从jar包加载
- 通过网络加载
- 把一个Java源文件动态编译,并执行加载
2、连接
当类被加载之后,系统为之生成一个对应的Class对象,接着进入连接阶段,连接阶段负责将类的二进制数据合并到JRE中。
类连接又可分为三个阶段:
(1)验证
- 文件格式验证
- 元数据验证
- 字节码验证
- 符号引用验证
(2)准备
为类的静态变量分配内存,并设置默认初始值。
(3)解析
将类的二进制数据中的符号引用替换成直接引用。
3、初始化
为类的静态变量赋予初始值。
十七、JVM的类加载机制是什么?
JVM类加载机制主要有三种:
1、全盘负责
类加载器加载某个class时,该class所依赖的和引用其它的class也由该类加载器载入。
2、双亲委派
先让父加载器加载该class,父加载器无法加载时才考虑自己加载。
3、缓存机制
缓存机制保证所有加载过的class都会被缓存,当程序中需要某个class时,先从缓存区中搜索,如果不存在,才会读取该类对应的二进制数据,并将其转换成class对象,存入缓存区中。
这就是为什么修改了class后,必须重启JVM,程序所做的修改才会生效的原因。
十八、什么是双亲委派模型?
如果一个类收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器执行,如果父加载器还存在其父加载器,则进一步向上委托,依次递归,请求将最终到达顶层的启动类加载器,如果父类加载器可以完成父加载任务,就成功返回,如果父加载器无法完成加载任务,子加载器才会尝试自己去加载,这就是双亲委派模型。
双亲委派模式的优势:
- 避免重复加载;
- 考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委派模式传递到启动加载器,而启动加载器在核心Java API中发现同名的类,发现该类已经被加载,就不会重新加载网络传递的Integer类,而直接返回已加载过的Integer.class,这样可以防止核心API库被随意篡改。