Java面试题(第三天)
1.HashMap和HashTable的区别?
a.区别
- 多线程环境下,HashTable比HashMap更安全,因为HashTable都加了一个synchronized修饰
- HashMap允许key和value为null,而HashTable不允许
b.HashMap底层实现
数组+链表
jdk8开始链表高度到8,数组长度超过64,链表转变为红黑树,元素以内部类Node节点存在
- 计算key的hash值,二次hash然后对数组长度取模,对应到数组下标
- 如果没有产生hash冲突(下标位置没有元素),则直接创建Node存入数组
- 如果产生hash冲突,先进行equals比较,相同则取代该元素,不同,则判断链表高度插入链表,链表高度达到8,并且数组长度到64则转变为红黑树,长度低于6则将红黑树转回链表
- key为null,存在下标0的位置
2.ConcurrentHashMap原理?JDK7和JDK8区别?
a.JDK7
数据结构:ReentrantLock+Segment+HashEntry,一个Segment中包含一个HashEntry数组,每个HashEntry又是一个链表结构
元素查询:二次hash,第一次Hash定位到Segment,第二次Hash定位到元素所在的链表的头部
锁:Segment分段锁Segment继承了ReentrantLock,锁定操作的Segment,其他的Segment不受影响,并发长度为Segment个数,可以通过构造函数制定,数组扩容不会影响其他的Segment
get方法无需加锁,volatile保证
b.JDK8
数据结构:synchronized+CAS+Node+红黑树,Node的val和next都用volatile修饰,保证可见性查找,替换,赋值操作都使用CAS
锁:锁链表的head节点,不影响其他元素的读写,锁粒度更细,效率更高,扩容时,阻塞所有的读写操作,并发扩容
读操作无锁:
Node的val和next使用volatile修饰,读写线程对该变量互相可见
数组用volatile修饰,保证扩容时被读线程感知
3.IOC容器
1.什么是IOC
控制反转IOC(Inversion of Control),是一种思想,DI(依赖注入)是实现IOC的一种方法,也有人认为DI只是IOC的另一种说法。没有IOC的程序中,我们使用面向切面编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
采用XML方式配置Bean的时候,Bean的定义信息和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
控制反转是一种描述(XML或注解)并通过第三方去生产或获取特定对象的方式,在Spring中实现控制反转的容器的IOC容器,其实现方法是依赖注入(Dependency Injection,DI).
2.如何实现一个IOC容器
1.配置文件配置包扫描路径
2.递归包扫描获取.class文件
3.反射,确定需要交给IOC管理的类
4.对需要注入的类进行依赖注入
- 配置文件中制定需要扫描的包路径
- 定义一些注解,分别表示访问控制层、业务服务层、数据持久层、依赖注入注解、获取配置文件注解
- 从配置文件中获取需要扫描的包路径,获取到当前路径下的文件信息及文件夹信息,我们将当前路径下所有以.class结尾的文件添加到一个Set集合中进行存储
- 遍历这个Set集合,获取在类上有制定注解的类,并将其交给IOC容器,定义一个安全的Map用来存储这些对象
- 遍历这个IOC容器,获取到每一个类的实例,判断里面是有依赖其他的类的实例,然后进行递归注入。
4.字节码
1.什么是字节码?
Java中的编译器和解释器:
Java中引入了虚拟机的概念,即在机器和编译程序之间加入了一层抽象的虚拟的机器,这台虚拟的机器在任何平台上都提供给编译程序一个共同的接口。
编译程序只需要面向虚拟机,生成虚拟机能够理解的代码,然后由解释器来将虚拟机代码转换为特定系统的机器码执行,在Java中,这种提供虚拟机理解的代码就叫做字节码(即扩展名为.class文件),它不面向任何特定的处理器,只面向虚拟机
每一种平台的解释器是不同的,但是实现的虚拟机是相同的,Java源程序经过编译器编译后变成字节码,字节码由虚拟机解释执行,虚拟机将每一条要执行的字节码发送个解释器,解释器将其翻译成特定机器上的机器码,然后在特定的机器上运行,这也解释了Java的编译与解释并存的特定
Java源代码---->编译器---->JVM可执行的Java字节码(即虚拟指令)---->jvm----->jvm中解释器--->机器可执行的二进制机器码--->程序运行。
字节码的作用是什么?
Java语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特定。所以Java程序运行时比较搞笑,而且,由于字节码并不专对一种特定的机器,因此,Java程序无需重新编译可以在多种不同的计算机上运行。
5.Java类加载器有哪些?
JDK自带有三个类加载器:bootstrap ClassLoader、extClassLoader、AppClassLoader
bootstrap ClassLoader是extClassLoader的父类加载器,默认负责加载%JAVA_HOME%lib下的jar包和class文件(父类不是直接的继承关系,有一个parent属性维护)
extClassLoader是AppClassLoader的父类加载器,负责加载%JAVA_HOME%lib/ext下的jar包和class类
AppClassLoader是自定以加载的父类,负责加载classpath下的类文件。系统加载器,线程上下文加载器
(意思就是这三个加载器中,app加载器贯穿于三个加载器,三个加载器都可以对其进行访问)
继承ClassLoader实现自定义类加载器
标签:面试题,Java,Segment,虚拟机,链表,IOC,加载 From: https://www.cnblogs.com/qisui/p/17806008.html