✨Lamda表达式的优缺点。
优点:
1. 简洁。
2. 非常容易并行计算。
3. 可能代表未来的编程趋势。
缺点:
1. 若不用并行计算,很多时候计算速度没有比传统的 for 循环快。(并行计算有时需要预热才显 示出效率优势)
2. 不容易调试。
3. 若其他程序员没有学过 lambda 表达式,代码不容易让其他语言的程 序员看懂。
与equlas有什么区别?
如果是基本类型,判断它们值是否相等;
如果是引用对象,判断两个对象指向的内存地址是否相同。
equals
如果是字符串,表示判断字符串内容是否相同;
如果是object对象的方法,比较的也是引用的内存地址值;
如果自己的类重写equals方法,可以自定义两个对象是否相等。
final关键字
当用final修饰一个类时,表明这个类不能被继承。“使用final方法的原因有两个。第一个原因是把方法 锁定,以防任何继承类修改它的含义;第二个原因是效率。
对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用 类型的变量,则在对其初始化之后便不能再让其指向另一个对象。
✨接口和抽象类的区别是什么
Java提供和支持创建抽象类和接口。它们的实现有共同点,不同点在于: 接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。 类可以实现很多个接口,但是只能继承一个抽象类 类可以不实现抽象类和接口声明的所有方法,当然,在这种情况下,类也必须得声明成是抽象的。 抽象类可以在不提供接口方法实现的情况下实现接口。 Java接口中声明的变量默认都是final的。抽象类可以包含非final的变量。 Java接口中的成员函数默认是public的。抽象类的成员函数可以是private,protected或者是public。 接口是绝对抽象的,不可以被实例化。抽象类也不可以被实例化,如果它包含main方法的话是可以被调用的。
✨请问什么是java序列化?以及如何实现java序列化
序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对 象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时 所引发的问题。
**java内存模型(Java Memory Model)**是java虚拟机规范定义的,用来屏蔽掉java程序在各种不同的硬件 和操作系统对内存的访问的差异,这样就可以实现java程序在各种不同的平台上都能达到内存访问的一 致性。可以避免像c++等直接使用物理硬件和操作系统的内存模型在不同操作系统和硬件平台下表现不 同,比如有些c/c++程序可能在windows平台运行正常,而在linux平台却运行有问题。
✨cookie 和 session 的区别
1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用 session。
3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服 务器性能方面,应当使用COOKIE。
4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
✨说说你对get和post请求,并且说说它们之间的区别
①get请求用来从服务器上获得资源,而post是用来向服务器提交数据;
②get将表单中数据按照name=value的形式,添加到action所指向的URL 后面,并且两者使用"?“连接,而各个变量之间使用”&"连接;post是将表单中的数据放在HTTP协议的请求头或消息体中,传递到 action所指向URL;
③get传输的数据要受到URL长度限制(1024字节);post可以传输大量的数据,上传文件通常要使用 post方式;
④使用get时参数会显示在地址栏上,如果这些数据不是敏感数据可以使用get;对于敏感数据还是应用使用post;
✨哈希
🎶HashMap的底层实现
底层由链表+数组实现 可以存储null键和null值 线性不安全 初始容量为16,扩容每次都是2的n次幂(保证位运算) 加载因子为0.75,当Map中元素总数超过Entry数组的0.75,触发扩容操作. 并发情况下,HashMap进行put操作会引起死循环,导致CPU利用率接近100%。
HashMap底层是数组和链表的结合。HashMap通过key的HashCode经过扰动函数处理过后得到Hash 值,然后通过位运算判断当前元素存放的位置,如果当前位置存在元素的话,就判断该元素与要存入的 元素的hash值以及key是否相同,如果相同的话,直接覆盖,不相同就通过拉链法解决冲突。当Map中 的元素总数超过Entry数组的0.75时,触发扩容操作,为了减少链表长度,元素分配更均匀。
HashMap基于哈希思想,实现对数据的读写。当我们将键值对传递给put()方法时,它调用 键对象的 hashCode()方法来计算hashcode,然后后找到bucket位置来储存值对象。当获取对象时,通过键对象 的equals()方法找到正确的键值对,然后返回值对象。HashMap使用链表 来解决碰撞问题,当发生碰 撞了,对象将会储存在链表的下一个节点中。HashMap在每个 链表节点中储存键值对对象。当两个不 同的键对象的hashcode相同时,它们会储存在同一个 bucket位置的链表中,可通过键对象的equals() 方法用来找到键值对。如果链表大小超过阈 值( 8),链表就会被改造为树形结构。rehash解决多次扩 容后数据分配问题
JDK1.8 以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)时,将链表转化为红 黑树,以减少搜索时间。 (一个是链表的长度达到8个,一个是数组的长度达到64个)
🎶为什么选择8才会选择使用红黑树
为了配合使用分布良好的hashCode,树节点很少使用。并且在理想状态下,受随机分布的hashCode 影响,链表中的节点遵循泊松分布,而且根据统计,链表中节点数是8的概率已经接近千分之一,而且 此时链表的性能已经很差了。所以在这种比较罕见和极端的情况下,才会把链表转变为红黑树。因为链 表转换为红黑树也是需要消耗性能的,特殊情况特殊处理,为了挽回性能,权衡之下,才使用红黑树, 提高性能。也就是大部分情况下,hashmap还是使用的链表,如果是理想的均匀分布,节点数不到8, hashmap就自动扩容。
🎶哈希冲突
如果两个不同对象的hashCode相同,这种现象称为hash冲突。
有以下的方式可以解决哈希冲突:
开放定址法
再哈希法
链地址法
建立公共溢出区
🎶HashMap和Hashtable的区别
HashMap和Hashtable都实现了Map接口,因此很多特性非常相似。但是,他们有以下不同点: HashMap允许键和值是null,而Hashtable不允许键或者值是null。 Hashtable是同步的,而HashMap不是。HashMap更适合于单线程环境,而Hashtable适合于多线程 环境。 HashMap提供了可供应用迭代的键的集合,因此,HashMap是快速失败的。
HashMap和TreeMap的区别
HashMap:数组方式存储key/value,线程非安全,允许null作为key和value,key不可以重复,value 允许重复,不保证元素迭代顺序是按照插入时的顺序,key的hash值是先计算key的hashcode值,然后 再进行计算,每次扩容会重新计算key的hash值,会消耗资源,要求key必须重写equals和hashcode方 法。它默认初始容量为16,加载因子0.75,扩容为旧容量的2倍,查找元素快,如果key一样则比较 value
如果value不一样,则按照链表结构存储value,就是一个key后面有多个value TreeMap:基于红黑树的NavigableMap实现,线程非安全,不允许null,key不可以重复,value允许重 复,存入TreeMap的元素应当实现Comparable接口或者实现Comparator接口,会按照排序后的顺序 迭代元素,两个相比较key不得抛出classCastException。主要用于存入元素的时候对元素进行自动排 序,迭代输出的时候就按照排序顺序输出。
🎶TreeMap的底层实现
TreeMap 的实现就是红黑树数据结构,一棵自平衡的排序二叉树,这样就可以保证当需要快速检索指定节点。
红黑树的插入、删除、遍历时间复杂度都为O(lgN),所以性能上低于哈希表。但是哈希表无法提供键值 对的有序输出,红黑树因为是排序插入的,可以按照键的值的大小有序输出。红黑树性质:
1.节点是红色或黑色。
2.根节点是黑色。
3.每个叶子节点都是黑色的空节点(NIL节点)。
4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
5.从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
平衡二叉树的性质
它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉 树。这个方案很好的解决了二叉查找树退化成链表的问题,把插入,查找,删除的时间复杂度最好情况 和最坏情况都维持在O(logN)。但是频繁旋转会使插入和删除牺牲掉O(logN)左右的时间,不过相对二叉查找树来说,时间上稳定了很多。
区别:
1、红黑树放弃了追求完全平衡,追求大致平衡,在与平衡二叉树的时间复杂度相差不大的情况下,保 证每次插入最多只需要三次旋转就能达到平衡,实现起来也更为简单。
2、平衡二叉树追求绝对平衡,条件苛刻,实现起来比较麻烦,每次插入新节点之后需要旋转的次数不能预知。
✨ArrayList和LinkedList的区别
ArrayList和LinkedList都实现了List接口,他们有以下的不同点: ArrayList是基于索引的数据接口,它的底层是数组。它可以以O(1)时间复杂度对元素进行随机访问。与 此对应,LinkedList是以元素列表的形式存储它的数据,每一个元素都和它的前一个和后一个元素链接 在一起,在这种情况下,查找某个元素的时间复杂度是O(n)。 相对于ArrayList,LinkedList的插入,添加,删除操作速度更快,因为当元素被添加到集合任意位置的 时候,不需要像数组那样重新计算大小或者是更新索引。 LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元 素,一个指向下一个元素。
✨数组(Array)和列表(ArrayList)的区别,什么时候应该使用Array而不是ArrayList
Array可以包含基本类型和对象类型,ArrayList只能包含对象类型。 Array大小是固定的,ArrayList的大小是动态变化的。 ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。 对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时 候,这种方式相对比较慢。
✨进程与线程的区别
1、进程是资源分配的最小单位,线程是程序执行的最小单位(资源调度的最小单位)
2、进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间, 而线程是共享进程中 的数据、地址空间
3、线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需 要以通信的方式(IPC)进行。
4、多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会 对另外一个进程造成影响,因为进程有自己独立的地址空间。
✨如何保证线程安全
通过合理的时间调度,避开共享资源的存取冲突。另外,在并行任务设计上可以通过适当的策略,保证 任务与任务之间不存在共享资源
✨详细描述一下线程从创建到死亡的几种状态都有哪些
新建( new ):新创建了一个线程对象。
可运行( runnable ):线程对象创建后,其他线程(比如 main 线程)调用了该对象 的 start ()方法。该状 态的线程位于可运行线程池中,等待被线程调度选中,获取 cpu 的使用权 。
运行( running ):可运行状态( runnable )的线程获得了 cpu 时间片( timeslice ) ,执行程序代码。
阻塞( block ):阻塞状态是指线程因为某种原因放弃了 cpu 使用权,阻塞的情况分三种: 等待阻塞、同步阻塞、其他阻塞。
死亡( dead ):线程 run ()、 main () 方法执行结束,或者因异常退出了 run ()方法,则该线程结束生命周期。死亡的线程不可再次复生。
✨什么是死锁(deadlock)
两个线程或两个以上线程都在等待对方执行完毕才能继续往下执行的时候就发生了死锁。结果就是这些 线程都陷入了无限的等待中。如何避免线程死锁? 只要破坏产生死锁的四个条件中的其中一个就可以了。 破坏互斥条件:这个条件我们没有办法破坏,因为我们用锁本来就是想让他们互斥的(临界资源需要互斥访问)。
破坏请求与保持条件:一次性申请所有的资源。
破坏不剥夺条件:占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的 资源。
破坏循环等待条件:靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。
✨JAVA中如何确保N个线程可以访问N个资源,但同时又不导致死锁
使用多线程的时候,一种非常简单的避免死锁的方式就是:指定获取锁的顺序,并强制线程按照指定的 顺序获取锁。因此,如果所有的线程都是以同样的顺序加锁和释放锁,就不会出现死锁了。
✨线程池有哪几个参数
Java通过Executors提供四种线程池,分别为:
1)newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线 程,若无可回收,则新建线程。
2)newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等 待。
3)newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
4)newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保 证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
✨参数
corePoolSize :核心线程数量
maximumPoolSize :线程最大线程数
workQueue :阻塞队列,存储等待执行的任务 很重要 会对线程池运行产生重大影响 keepAliveTime :线程没有任务时最多保持多久时间终止
unit :keepAliveTime的时间单位
threadFactory :线程工厂,用来创建线程
rejectHandler :当拒绝处理任务时的策略
✨synchronized关键字和volatile关键字比较
volatile关键字是线程同步的轻量级实现,所以volatile性能肯定比synchronized关键字要好。 多线程访问volatile关键字不会发生阻塞,而synchronized关键字可能会发生阻塞 volatile关键字能保证数据的可见性,但不能保证数据的原子性。synchronized关键字两者都能保证。 volatile关键字主要用于解决变量在多个线程之间的可见性,而 synchronized关键字解决的是多个线程 之间访问资源的同步性。
✨线程池运行原理分析
1、创建一个线程池,在还没有任务提交的时候,默认线程池里面是没有线程的。也可以调用 prestartCoreThread方法,来预先创建一个核心线程。
2、线程池里还没有线程或者线程池里存活的线程数小于核心线程数corePoolSize时,这时对于一个新 提交的任务,线程池会创建一个线程去处理提交的任务。此时线程池里面的线程会一直存活着,就算空 闲时间超过了keepAliveTime,线程也不会被销毁,而是一直阻塞在那里一直等待任务队列的任务来执 行。
3、当线程池里面存活的线程数已经等于corePoolSize了,对于一个新提交的任务,会被放进任务队列 workQueue排队等待执行。而之前创建的线程并不会被销毁,而是不断的去拿阻塞队列里面的任务, 当任务队列为空时,线程会阻塞,直到有任务被放进任务队列,线程拿到任务后继续执行,执行完了过 后会继续去拿任务。这也是为什么线程池队列要是用阻塞队列。
4、当线程池里面存活的线程数已经等于corePoolSize了,并且任务队列也满了,这里假设 maximumPoolSize>corePoolSize(如果等于的话,就直接拒绝了),这时如果再来新的任务,线程池就会 继续创建新的线程来处理新的任务,知道线程数达到maximumPoolSize,就不会再创建了。这些新创 建的线程执行完了当前任务过后,在任务队列里面还有任务的时候也不会销毁,而是去任务队列拿任务 出来执行。在当前线程数大于corePoolSize过后,线程执行完当前任务,会有一个判断当前线程是否需 要销毁的逻辑:如果能从任务队列中拿到任务,那么继续执行,如果拿任务时阻塞(说明队列中没有任 务),那超过keepAliveTime时间就直接返回null并且销毁当前线程,直到线程池里面的线程数等于 corePoolSize之后才不会进行线程销毁。
5、如果当前的线程数达到了maximumPoolSize,并且任务队列也满了,这种情况下还有新的任务过 来,那就直接采用拒绝的处理器进行处理。默认的处理器逻辑是抛出一个异常。
✨线程池有什么优势
第一:降低资源消耗。
第二:提高响应速度。
第三:提高线程的可管理性
✨垃圾回收的优点以及原理
使得Java程序员在编写程序的时候不再需要考虑内存管理。由于有个垃圾回收机制,Java中的对象不再 有"作用域"的概念,只有对象的引用才有"作用域"。垃圾回收可以有效的防止内存泄露,有效的使用可 以使用的内存。垃圾回收器通常是作为一个单独的低级别的线程运行,不可预知的情况下对内存堆中已 经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或 所有对象进行垃圾回收。不再会被使用的对象的内存不能被回收,就是内存泄露
🎆判断对象是否可回收的方法
==================
引用计数法:给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加 1;当引用失效,计数 器就减 1;任何时候计数器为 0 的对象就是不可能再被使用的 可达性分析法:通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过 的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的 强引用、软引用、弱引用、虚引用(虚引用与软引用和弱引用的区别、软引用能带来的好处)
✨强引用
以前我们使用的大部分引用实际上都是强引用,这是使用最普遍的引用。如果一个对象具有强引用,那 就类似于必 不可少的生活用品,垃圾回收器绝不会回收它。当内存空 间不足,Java 虚拟机宁愿抛出 OutOfMemoryError 错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。
✨软引用
如果一个对象只具有软引用,那就类似于可有可无的生活用品。如果内存空间足够,垃圾回收器就不会 回收它,如 果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使 用。软引用可 用来实现内存敏感的高速缓存。 软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收, JAVA 虚拟机就会把这个软引用加入到与之关联的引用队列中。
✨弱引用
如果一个对象只具有弱引用,那就类似于可有可无的生活用品。弱引用与软引用的区别在:只具有弱引 用的对象 拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具有弱引 用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低 的线程, 因此不一定会很快发现那些只具有弱引用的对象。 弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收, Java 虚拟机就 会把这个弱引用加入到与之关联的引用队列中。
✨虚引用
虚引用主要用来跟踪对象被垃圾回收的活动 ,在程序设计中一般很少使用弱引用与虚引用,使用软引用 的情况较多,因为软引用可以加速 JVM对垃圾内存的回收速度,可以维护系统的运行安全,防止内存溢 出等问题的产生**, 如何判断一个常量是废弃常量 运行时常量池主要回收的是废弃的常量。 假如在常量池中存在字符串 “abc”,如果当前没有任何 String 对象引用该字符串常量的话,就说明常量 “abc” 就是 废弃常量,如果这时发生内存回收的话而且有必要的话,“abc” 就会被系统清理出常量池。
🎆判断一个类是无用的类
================
方法区主要回收的是无用的类,类需要同时满足下面 3 个条件才能算是 “无用的类” :
1、该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。
2、加载该类的 ClassLoader 已经被回收。
3、该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
🎆垃圾回收算法
✨标记-清除算法
算法分为“标记”和“清除”阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的 对象。它是最基础的收集算法,效率也很高,但是会带来两个明显的问题:\1. 效率问题\2. 空间问题。
✨复制算法
为了解决效率问题,“复制”收集算法出现了。它可以将内存分为大小相同的两块,每次使用其中的一 块。当这一块 的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。这样就使每次 的内存回收 都是对内存区间的一半进行回收。
✨标记-整理算法
根据老年代的特点特出的一种标记算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对 可回收对象回收,而是让所有存活的对象向一端移动,然后直接清理掉端边界以外的内存。
✨分代收集算法
当前虚拟机的垃圾收集都采用分代收集算法,根据对象存活周期的不同将内存分为几块。一般将 java 堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。 比如在新生代中,每次收集都会有大量对象死去,所以可以选择复制算法,只需要付出少量对象的复制 成本就可以 完成每次垃圾收集。而老年代的对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,所 以我们必须 选择“标记-清除”或“标记-整理”算法进行垃圾收集。
🎆HTTP和HTTPS的区别
===================
https需要到ca申请证书,因而需要一定费用 http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议,成本较高 http的连接很简单,是无状态的,https协议是由ssl+http协议构建的可进行加密串苏,身份验证的网络 协议 http用的端口是80,https用的端口是443
🎆浏览器中输入一个URL后,按下回车后发生了什么
=============================
URL,统一资源定位符,l简单点就是网址=ip或域名 + 端口号 + 资源位置 + 参数 + 锚点
1.输入一个网址之后,首先浏览器通过查询DNS,查找这个URL的IP地址,(通过层层向上级DNS服 务器查找直到找到对应URL的IP地址)
2.得到目标服务器的IP地址及端口号(http 80端口,https 443端口),会调用系统库函数socket,请 求一个TCP流套接字。客户端向服务器发送HTTP请求报文。
(1)应用层:客户端发送HTTP请求报文。
(2)传输层:(加入源端口、目的端口)建立连接。实际发送数据之前,三次握手客户端和服务器建 立起一个TCP连接。
(3)网络层:(加入IP头)路由寻址。
(4)数据链路层:(加入frame头)传输数据。
(5)物理层:物理传输bit。
3.服务器端经过物理层→数据链路层→网络层→传输层→应用层,解析请求报文,发送HTTP响应报文。
4.关闭连接,TCP四次挥手。
5.客户端解析HTTP响应报文,浏览器开始显示HTML
🎆TCP怎么实现可靠传输
=================
确认和重传机制:建立连接、发送包时的确认,运输过程中校验失败、丢包或延时发送端重传
数据排序:把数据分成很多包,按顺序进行传输