网站建设的创意,如何做好营销,网站开发技术考试试卷,如何制作旅游网站大家好#xff0c;我是烤鸭#xff1a; 今天分享一些Java面试题和答案。 这些答案都是自己想的#xff0c;如果有理解不一样的#xff0c;欢迎交流。 部分原题来自#xff1a; https://blog.csdn.net/qq_41790443/article/details/80694415 1. HashMap的源码#xff0…大家好我是烤鸭 今天分享一些Java面试题和答案。 这些答案都是自己想的如果有理解不一样的欢迎交流。 部分原题来自 https://blog.csdn.net/qq_41790443/article/details/80694415 1. HashMap的源码实现原理JDK8中对HashMap做了怎样的优化 首先说一下HashMap是什么大部分人会说数组链表键值允许为null。 我说说我的想法。HashMap内部类Node实现了Entry。四个属性hash值next节点地址值key和value。
是存放在数组中。 HashMap初始化的时候会创建一个默认大小为16的数组默认负载因子0.75当数组大小为16*0.7512时会发生扩容。 JDK8 优化HashMap数组初始化会在put方法时检查如果数组为空再去创建数组。JDK7 是初始化时都创建好了。 putVal方法中的hash()方法是key的高16位异或低16位实现的比JDK7 更简单有效。 JDK8 优化相同hashcode的会接在链表的末尾。当链表长度大于8时会变成红黑树。JDK7 一直是链表。 JDK8 优化resize()方法遍历旧数组oldTab[j]放入newTab中e.hash (newCap - 1)的位置链表重排时原数组[j]位置上的桶移到了新数组[j原数组长度]。JDK7 resize()扩容后链表的顺序与原来相反。 上面红色部分移位运算a % (2^n) 等价于 a (2^n - 1)由于(hashCode中)新增的1bit是0还是1可以认为是随机的因此resize的过程均匀的把之前的冲突的节点分散到新的bucket了。 更多有关于HashMap的内容推荐两篇博客 https://www.jianshu.com/p/17177c12f849 https://tech.meituan.com/java_hashmap.html 2. HaspMap扩容是怎样扩容的为什么都是2的N次幂的大小。 发生条件当 数组中元素个数 超过 数组大小 * 负载因子时就会发生扩容。 过程简述JDK 8 为例源码就不贴了只是简单说一下过程。 如果原数组大小是0创建新数组初始化数组大小和负载因子以及当前负载因子发生扩容时的数组大小。如果原数组已经超过数组的大小的最大值(2的30次方)就将数组大小置成Integer最大值(2的31次方 - 1)。 如果是 0 - 2的30次方 之间的扩容2倍。 遍历数组判断是否是末节点如果是的话就把当前元素放到新数组[e.hash (newCap - 1)]位置上等价于a % (2^n)。如果不是判断是否是红黑树节点如果是树节点遍历当前节点及后续节点判断是否 (e.hash bit 0) bit是原数组大小添加节点时 e.hash bit 完全是随机的所以判断末尾是0还是1来决定是高位还是低位节点。不是树节点的情况其实类似树节点也是判断e.hash oldCap 0原数组[j]位置上的桶移到了新数组[j]。e.hash oldCap 0,原数组[j]位置上的桶移到了新数组[j原数组长度]。
关于2的n次幂a % (2^n) 等价于 a (2^n - 1)。
HashMap底层数组的长度总是2的n次方这是HashMap在速度上的优化。当length总是2的n次方时h (length-1)运算等价于对length取模也就是h%length但是比%具有更高的效率。 3. HashMapHashTableConcurrentHashMap的区别。
HashMap 允许一个NULL键和多个NULL值。非线程安全。HashMap实现线程安全可以采用Collections.synchronizedMap(map) HashTable 不允许NULL键和NULL值。线程安全。使用synchronized来锁住整张Hash表来实现线程安全即每次锁住整张表让线程独占。 ConcurrentHashMapjdk7 允许多个修改操作并发进行其关键在于使用了锁分离技术。它使用了多个锁来控制对hash表的不同部分进行的修改。ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分每个段其实就是一个小的Hashtable它们有自己的锁。只要多个修改操作发生在不同的段上它们就可以并发进行。 (jdk8) 摒弃了Segment的概念而是直接用Node数组链表红黑树的数据结构来实现并发控制使用Synchronized和CAS来操作整个看起来就像是优化过且线程安全的HashMap虽然在JDK1.8中还能看到Segment的数据结构但是已经简化了属性只是为了兼容旧版本。 并发的多线程使用场景中使用HashMap可能造成死循环(jdk7)HashTable效率太低不适合在高并发情况下使用应该使用线程安全的ConcurrentHashMap。 https://www.cnblogs.com/zq-boke/p/8654539.html 4. 极高并发下HashTable和ConcurrentHashMap哪个性能更好为什么如何实现的。 ConcurrentHashMap 性能更好。 jdk 1.8以后HashTable已经淘汰了并发时使用一把锁处理并发问题当有多个线程访问时需要多个线程竞争一把锁导致阻塞。 jdk 1.7 ConcurrentHashMap则使用分段相当于把一个HashMap分成多个然后每个Segment分配一把锁这样就可以支持多线程访问。 jdk 1.8 ConcurrentHashMap取消segments字段直接采用transient volatile HashEntryK,V table保存数据采用table数组元素作为锁从而实现了对每一行数据进行加锁进一步减少并发冲突的概率。 并发控制使用Synchronized和CAS来操作。JDK8中的实现也是锁分离思想只是锁住的是一个node而不是JDK7中的Segment锁住Node之前的操作是基于在volatile和CAS之上无锁并且线程安全的。 5. HashMap在高并发下如果没有处理线程安全会有怎样的安全隐患具体表现是什么。 jdk1.7 在并发的多线程使用场景中使用HashMap可能造成死循环,put过程中的resize方法在调用transfer方法的时候导致的死锁。 jdk1.8 会将原来的链表结构保存在节点e中然后依次遍历e,根据hashn是否等于0,分成两条支链保存在新数组中。 但是有可能出现数据丢失的情况。 6. java中四种修饰符的限制范围。
private 本类 default 本包下其他类 protected 不同包下子类 public 不同包下非子类
7. Object类中的方法 equals hashCode toString getClass notify notifyAll wait * 3
8. 接口和抽象类的区别注意JDK8的接口可以有实现。 抽象类子类继承关系是“是一种”。接口子类实现关系是“有一种”。 以jdk 1.8为例 抽象类的方法可以声明default修饰方法interface只能用public static修饰。 抽象类中的成员变量可以是各种类型的而接口中的成员变量只能是public static final类型的。 接口中不能含有静态代码块而抽象类可以有静态代码块。 一个类只能继承一个抽象类而一个类却可以实现多个接口。 9. 动态代理的两种方式以及区别。 JDK动态代理利用反射机制生成一个实现代理接口的匿名类在调用具体方法前调用InvokeHandler来处理。 CGlib动态代理利用ASM开源的Java字节码编辑库操作字节码开源包将代理对象类的class文件加载进来通过修改其字节码生成子类来处理。 区别JDK代理只能对实现接口的类生成代理CGlib是针对类实现代理对指定的类生成一个子类并覆盖其中的方法这种通过继承类的实现方式不能代理final修饰的类。 1. JDK代理使用的是反射机制实现aop的动态代理CGLIB代理使用字节码处理框架asm通过修改字节码生成子类。 所以jdk动态代理的方式创建代理对象效率较高执行效率较低cglib创建效率较低执行效率高 2. JDK动态代理机制是委托机制具体说动态实现接口类在动态生成的实现类里面委托hanlder去调用原始实现类方法。 CGLIB则使用的继承机制具体说被代理类和代理类是继承关系所以代理类是可以赋值给被代理类的如果被代理类有接口那么代理类也可以赋值给接口。 https://blog.csdn.net/weixin_36759405/article/details/82770422 10. Java序列化的方式。 序列化就是把Java对象储存在某一地方硬盘、网络也就是将对象的内容进行流化二进制。 Java Serialization主要是采用JDK自带的Java序列化实现性能很不理想 Json目前有两种实现一种是采用的阿里的fastjson库另一种是采用dubbo中自己实现的简单json库还有谷歌的Gson Hession它基于HTTP协议传输使用Hessian二进制序列化对于数据包比较大的情况比较友好。 Dubbo Serialization阿里dubbo序列化 FST高性能、序列化速度大概是JDK的4-10倍大小是JDK大小的1/3左右 Protocol Buffer(Google出品的一种轻量 高效的结构化数据存储格式性能比 Json、XML 强) kryo(比kyro更高效的序列化库就只有google的protobuf了) 关于kryo,https://blog.csdn.net/eguid_1/article/details/79316403 11. 传值和传引用的区别Java是怎么样的有没有传值引用。 java函数中的参数都是传递值的所不同的是对于基本数据类型传递的是参数的一份拷贝对于类类型传递的是该类参数的引用的拷贝。 当在函数体中修改参数值时无论是基本类型的参数还是引用类型的参数修改的只是该参数的拷贝不影响函数实参的值如果修改的是引用类型的成员值则该实参引用的成员值是可以改变的。
https://www.cnblogs.com/zhangj95/p/4184180.html 12. 一个ArrayList在循环过程中删除会不会出问题为什么。 这里只考虑单线程的问题ArrayList线程不安全。 循环方式不同结果不同 增强for循环它对索引的边界值只会计算一次,使用list的remove方法会改变modCount值校验和expectedModCount不一 样有可能抛出ConcurrentModificationException。 普通for循环由于remove方法会调用System.arraycopy改变数组元素排序有可能抛出IndexOutOfBoundsException。 iterator循环iterator.remove()方法来移除元素是没有问题的。迭代器的remove方法每次会expectedModCount值改成modCount。
参考https://www.cnblogs.com/hupu-jr/p/7891844.html 13. Transactional注解在什么情况下会失效为什么。 方法不是public的 异常类型是不是unchecked异常(解决方案rollbackForException.class) 数据库引擎要支持事务如果是MySQL注意表要使用支持事务的引擎比如innodb如果是myisam事务是不起作用的 是否开启了对注解的解析 spring是否扫描这个包 同一个类中的方法调用 异常被catch
14. List 和 Set 的区别 都是实现Collection接口的。 List1.可以允许重复的对象。 2.可以插入多个null元素。 3.是一个有序容器保持了每个元素的插入顺序输出的顺序就是插入的顺序。 4.常用的实现类有 ArrayList、LinkedList 和 Vector。ArrayList 最为流行它提供了使用索引的随意访问而 LinkedList 则对于经常需要从 List 中添加或删除元素的场合更为合适。 Set1.不允许重复对象 2. 无序容器你无法保证每个元素的存储顺序TreeSet通过 Comparator 或者 Comparable 维护了一个排序顺序。 3. 只允许一个 null 元素 4.Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap 实现的 HashSetTreeSet 还实现了 SortedSet 接口因此 TreeSet 是一个根据其 compare() 和 compareTo() 的定义进行排序的有序容器。 详细的解释https://www.cnblogs.com/IvesHe/p/6108933.html 15. HashSet 是如何保证不重复的 HashSet内部是HashMap,调用set的add方法就是调用map的put方法。 我们知道HashMap的key是不重复的。 根据hashCode和equals判断是否重复。
16. Java反射机制?功能实际使用 JAVA反射机制是在运行状态中对于任意一个类都能够知道这个类的所有属性和方法 对于任意一个对象都能够调用它的任意一个方法和属性这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。 部分信息是source阶段不清晰需要在runtime阶段动态临时加载。 获取class对象: 1 ClassName.getClass() 2 ClassName.class 3 Class.forName(String className); 获取构造方法和创建实例: clazz.getConstructors()(构造方法) constructor.newInstance()创建对象。 获取共有或私有方法: clazz.getDeclaredMethod获取方法,invoke(newInstance)调用方法。 获取注解: clazz.getAnnotations(); 最常见应用 利用反射获取配置文件内容。 对象转Map,对象转json。 文件复制。 springIOC 和 aop,Hibernate 和mybatis 很多框架用到了。 反射可以跳过泛型检查。 https://blog.csdn.net/yongjian1092/article/details/7364451 17. Arrays.sort 实现原理和 Collection 实现原理
当调用Arrays.sort(Object[] objects)时先调用的是归并的sort方法。 对于归并排序的改进 以上方法对给定数组的指定区间内的数据进行排序同时允许调用者提供用于归并排序的辅助空间。 实现思路为首先检查数组的大小如果数组比较小(286)则直接调用改进后的快速排序完成排序 如果数组较大则评估数组的无序程度如果这个数组几乎是无序的那么同样调用改进后的快速排序算法排序 如果数组基本有序那么采用归并排序算法对数组进行排序。 ·对于快速排序的改进 该算法的实现了一种称为“DualPivotQuicksort”的排序算法中文可以翻译为“双枢轴快速排序”可以看作是经典快速排序算法的变体。 算法的基本思路是如果数组的数据量较少(47)则执行插入排序就可以达到很好的效果如果数据量较大 那么确定数组的5个分位点选择一个或两个分位点作为“枢轴”然后根据快速排序的思想进行排序。
Collections.sort时 调用的也是Arrays.sort再将排好序的值set进去。 Array.sort调用的是TimSortTimSort算法是一种起源于归并排序和插入排序的混合排序算法。 如果数组小于MIN_MERGE32则调用binarySort使用二分查找的方法将后续的数插入之前的已排序数组。 大于MIN_MERGE 选取minRun(数组长度右移直到小于 MIN_MERGE)。找到初始升序序列如果降序会对其翻转。 若这组区块大小小于minRun则将后续的数补足利用binarySort 对run 进行扩展。入栈需要合并的数组。 合并数组重复以上的步骤。
Arrays.sort :https://blog.csdn.net/octopusflying/article/details/52388012 Collections.sort:https://blog.csdn.net/bruce_6/article/details/38299199https://www.jianshu.com/p/1efc3aa1507b 18. LinkedHashMap的应用
HashMap是无序的,LinkedHashMap是有序的,且默认为插入顺序。 LinkedHashMap是继承于HashMap是基于HashMap和双向链表来实现的。 HashMap无序LinkedHashMap有序可分为插入顺序和访问顺序两种。如果是访问顺序那put和get操作已存在的Entry时都会把Entry移动到双向链表的表尾(其实是先删除再插入)。 LinkedHashMap存取数据还是跟HashMap一样使用的Entry[]的方式双向链表只是为了保证顺序。 LinkedHashMap是线程不安全的。
https://www.jianshu.com/p/8f4f58b4b8ab 19. cloneable接口实现原理
实现clone接口的类调用clone方法属于深拷贝。 复制出来的对象属于不同的地址改变复制对象的属性值不会影响原对象。 浅拷贝的话拷贝的对象和原有的对象指向同一个地址值改变其中的属性值 另一个也会改变。
https://blog.csdn.net/u013916933/article/details/51590332
20. 数组在内存中如何分配
数组引用变量是存放在栈内存(stack)中数组元素是存放在堆内存(heap)中。 数组初始化分为静态初始化(在定义时就指定数组元素的值此时不能指定数组长度否则就出现了静态加动态混搭初始化数组了) 动态初始化(只指定数组长度由系统分配初始值初始值根据定义的数据类型来)。 堆中变量没有引用会等待垃圾回收。 栈中变量会在脱离作用域后释放。
https://blog.csdn.net/lcl19970203/article/details/54428358https://www.cnblogs.com/duanxz/p/6102583.html
21. BlockingQueue的使用及实现
利用 LinkedBlockingQueue 实现生产者和消费者队列伪代码如下
//消费者
class Consumer implements Runnable{private BlockingQueueString queue;public Consumer(BlockingQueueString queue) {this.queue queue;}public void run() {while (true) {String data queue.poll(2, TimeUnit.SECONDS);}}
}
//生产者
class Producer implements Runnable{private BlockingQueue queue;public Producer(BlockingQueue queue) {this.queue queue;}public void run() {while (true) {//延迟2s入数据queue.offer(data, 2, TimeUnit.SECONDS);}}
}
//测试类
TestBlockingQueue{Testpublic void test(){BlockingQueueString queue new LinkedBlockingQueueString(10);Producer producer1 new Producer(queue);Producer producer2 new Producer(queue);Producer producer3 new Producer(queue);Consumer consumer new Consumer(queue);// 借助ExecutorsExecutorService service Executors.newCachedThreadPool();// 启动线程service.execute(producer1);service.execute(producer2);service.execute(producer3);service.execute(consumer);}
}
http://www.cnblogs.com/jackyuj/archive/2010/11/24/1886553.html
22. BIO、NIO、AIO区别
Blocking IO(同步阻塞) 面向流阻塞。
Non-Blocking IO同步非阻塞 面向块(buffer)非阻塞。 非阻塞IO模型 如果没有数据立即返回EWOULDBLOCK。 用户线程不断轮询(polling)内核是否有数据。 有数据后由OS拷贝数据到内核缓冲区再由内核缓冲区拷贝到用户线程缓冲区。
IO复用模型 (select pool 无差别的轮询方式) 多个I/O的阻塞复用到同一个select阻塞上。 由多路复用器不断轮询(poll) I/O线程看看是否有数据。 如果没有数据就把当前线程阻塞如果有数据就唤醒轮询一遍所有的流。
(epool 最小轮询方式) 通过epoll方式来观察多个流epoll只会把发生了I/O事件的流通知我们。 时间复杂度降低为O(k),k为发生事件的流的个数。 如果所有的IO都是短连接且事件发生的比较快epoll和select poll效率差不多。
epoll相比于select/poll的优势: 监视的描述符数量不受限制所支持的FD上限是最大可以打开文件的数目 I/O效率不会随着监视fd的数量增长而下降。 epoll不同于select和poll轮询的方式而是通过每个fd定义的回调函数来实现的只有就绪的fd才会执行回调函数。
信号驱动模型 类似epoll,需要开启Socket的信号驱动式I/O功能通过sigaction系统调用来安装一个信号处理函数。 当有数据的时候内核就为该进程产生一个SIGIO信号,通过该信号的值做处理。
Asynchronous IO 收到用户请求立刻返回不会阻塞用户进程。 等待数据完成后将数据拷贝到用户内存然后发出一个信号。
https://blog.csdn.net/historyasamirror/article/details/5778378https://www.jianshu.com/p/db5da880154ahttps://www.jianshu.com/p/439e8b349f48
23. 事务隔离级别 和 事务传播级别
五大隔离级别 ISOLATION_DEFAULT默认级别 ISOLATION_READ_UNCOMMITTED读未提交可能导致脏读、幻读、重复读 ISOLATION_READ_COMMITTED 读已提交可能导致幻读、重复读 ISOLATION_REPEATABLE_READ不可重复读可能导致幻读 ISOLATION_SERIALIZABLE 通过锁表避免以上情况
七个传播级别PROPAGATION_REQUIRED如果没有事务就新建一个。 PROPAGATION_SUPPORTS按当前事务执行如果当前没有事务就按没事务的方式执行。 PROPAGATION_MANDATORY表示该方法必须运行在一个事务中。如果当前没有事务正在发生将抛出一个异常。PROPAGATION_REQUIRES_NEW创建新的事务如果存在事务旧的事务会挂起。 PROPAGATION_NOT_SUPPORTED以无事务的方式运行。PROPAGATION_NESTED 如果已有事务就嵌套事务。没有的话按 PROPAGATION_REQUIRED 处理。 ISOLATION_DEFAULT使用数据库的默认隔离级别。
24. http的七层协议
网络七层协议由下往上分别为物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。 TCP/IP五层模型应用层、传输层、网络层、数据链路层和物理层。
https://blog.csdn.net/a5582ddff/article/details/77731537
25. ArrayList怎么实现扩容 新的容量原来容量的1.5倍。 调用Arrays.copyOf()。
https://blog.csdn.net/eases_stone/article/details/79843851