京东阿里Java高级面试题(List和Set比较,各自的子类比较)

List和Set比较,各自的子类比较前端

对比一: Arraylist与LinkedList的比较java

一、ArrayList是实现了基于动态数组的数据结构,由于地址连续,一旦数据存储好了,查询操做效率会比较高(在内存里是连着放的)。面试

二、由于地址连续, ArrayList要移动数据,因此插入和删除操做效率比较低。   redis

三、LinkedList基于链表的数据结构,地址是任意的,因此在开辟内存空间的时候不须要等一个连续的地址,对于新增和删除操做add和remove,LinedList比较占优点。算法

四、由于LinkedList要移动指针,因此查询操做性能比较低。spring

适用场景分析:数据库

当须要对数据进行对此访问的状况下选用ArrayList,当须要对数据进行屡次增长删除修改时采用LinkedList。编程

对比二: ArrayList与Vector的比较后端

一、Vector的方法都是同步的,是线程安全的,而ArrayList的方法不是,因为线程的同步必然要影响性能。所以,ArrayList的性能比Vector好。 
二、当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增长50%的大小,这样。ArrayList就有利于节约内存空间。数组

三、大多数状况不使用Vector,由于性能很差,可是它支持线程的同步,即某一时刻只有一个线程可以写Vector,避免多线程同时写而引发的不一致性。

四、Vector能够设置增加因子,而ArrayList不能够。

适用场景分析:

一、Vector是线程同步的,因此它也是线程安全的,而ArrayList是线程异步的,是不安全的。若是不考虑到线程的安全因素,通常用ArrayList效率比较高。

二、若是集合中的元素的数目大于目前集合数组的长度时,在集合中使用数据量比较大的数据,用Vector有必定的优点。

对比三: HashSet与TreeSet的比较

1.TreeSet 是二叉树实现的,Treeset中的数据是自动排好序的,不容许放入null值 。

2.HashSet 是哈希表实现的,HashSet中的数据是无序的,能够放入null,但只能放入一个null,二者中的值都不能重复,就如数据库中惟一约束 。

3.HashSet要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码做为标识的,而具备相同内容的String对象,hashcode是同样,因此放入的内容不能重复。可是同一个类的对象能够放入不一样的实例。

适用场景分析:

HashSet是基于Hash算法实现的,其性能一般都优于TreeSet。咱们一般都应该使用HashSet,在咱们须要排序的功能时,咱们才使用TreeSet。

HashMap和ConcurrentHashMap的区别

一、HashMap不是线程安全的,而ConcurrentHashMap是线程安全的。

二、ConcurrentHashMap采用锁分段技术,将整个Hash桶进行了分段segment,也就是将这个大的数组分红了几个小的片断segment,并且每一个小的片断segment上面都有锁存在,那么在插入元素的时候就须要先找到应该插入到哪个片断segment,而后再在这个片断上面进行插入,并且这里还须要获取segment锁。

三、ConcurrentHashMap让锁的粒度更精细一些,并发性能更好。

至于二者的底层实现,你若是想经过一篇文章就理解了,那就too young了,好好找些博文+看源码去吧。

HashTable和ConcurrentHashMap的区别

它们均可以用于多线程的环境,可是当Hashtable的大小增长到必定的时候,性能会急剧降低,由于迭代时须要被锁定很长的时间。由于ConcurrentHashMap引入了分割(segmentation),不论它变得多么大,仅仅须要锁定map的某个部分,而其它的线程不须要等到迭代完成才能访问map。简而言之,在迭代的过程当中,ConcurrentHashMap仅仅锁定map的某个部分,而Hashtable则会锁定整个map。

String,StringBuffer和StringBuilder的区别

一、运行速度,或者说是执行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer > String。

二、线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的。

适用场景分析:

String:适用于少许的字符串操做的状况

StringBuilder:适用于单线程下在字符缓冲区进行大量操做的状况

StringBuffer:适用多线程下在字符缓冲区进行大量操做的状况

    • *

wait和sleep的区别

一、sleep()方法是属于Thread类中的,而wait()方法,则是属于Object类中的。

二、sleep()方法致使了程序暂停执行指定的时间,让出cpu给其余线程,可是他的监控状态依然保持着,当指定的时间到了又会自动恢复运行状态。因此在调用sleep()方法的过程当中,线程不会释放对象锁。

三、调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。

JVM的内存结构

根据 JVM 规范,JVM 内存共分为虚拟机栈、堆、方法区、程序计数器、本地方法栈五个部分。

一、Java虚拟机栈:

线程私有;每一个方法在执行的时候会建立一个栈帧,存储了局部变量表,操做数栈,动态链接,方法返回地址等;每一个方法从调用到执行完毕,对应一个栈帧在虚拟机栈中的入栈和出栈。

二、堆:

线程共享;被全部线程共享的一块内存区域,在虚拟机启动时建立,用于存放对象实例。

三、方法区:

线程共享;被全部线程共享的一块内存区域;用于存储已被虚拟机加载的类信息,常量,静态变量等。

四、程序计数器:

线程私有;是当前线程所执行的字节码的行号指示器,每条线程都要有一个独立的程序计数器,这类内存也称为“线程私有”的内存。

五、本地方法栈:

线程私有;主要为虚拟机使用到的Native方法服务。

强引用,软引用和弱引用的区别

强引用:

只有这个引用被释放以后,对象才会被释放掉,只要引用存在,垃圾回收器永远不会回收,这是最多见的New出来的对象。

软引用:

内存溢出以前经过代码回收的引用。软引用主要用户实现相似缓存的功能,在内存足够的状况下直接经过软引用取值,无需从繁忙的真实来源查询数据,提高速度;当内存不足时,自动删除这部分缓存数据,从真正的来源查询这些数据。

弱引用:

第二次垃圾回收时回收的引用,短期内经过弱引用取对应的数据,能够取到,当执行过第二次垃圾回收时,将返回null。弱引用主要用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾,能够经过弱引用的isEnQueued方法返回对象是否被垃圾回收器标记。

数组在内存中如何分配

一、简单的值类型的数组,每一个数组成员是一个引用(指针),引用到栈上的空间(由于值类型变量的内存分配在栈上)

二、引用类型,类类型的数组,每一个数组成员还是一个引用(指针),引用到堆上的空间(由于类的实例的内存分配在堆上)

springmvc的核心是什么,请求的流程是怎么处理的,控制反转怎么实现的

核心:

控制反转和面向切面

请求处理流程:

一、首先用户发送请求到前端控制器,前端控制器根据请求信息(如URL)来决定选择哪个页面控制器进行处理并把请求委托给它,即之前的控制器的控制逻辑部分;

二、页面控制器接收到请求后,进行功能处理,首先须要收集和绑定请求参数到一个对象,并进行验证,而后将命令对象委托给业务对象进行处理;处理完毕后返回一个ModelAndView(模型数据和逻辑视图名);

三、前端控制器收回控制权,而后根据返回的逻辑视图名,选择相应的视图进行渲染,并把模型数据传入以便视图渲染;

四、前端控制器再次收回控制权,将响应返回给用户。

控制反转如何实现:

咱们每次使用spring框架都要配置xml文件,这个xml配置了bean的id和class。

spring中默认的bean为单实例模式,经过bean的class引用反射机制能够建立这个实例。

所以,spring框架经过反射替咱们建立好了实例而且替咱们维护他们。

A须要引用B类,spring框架就会经过xml把B实例的引用传给了A的成员变量。

mybatis如何处理结果集

MyBatis的结果集是经过反射来实现的。并非经过get/set方法。在实体类中不管是否认义get/set()方法,都是能够接收到的。

若是面试只是考你这个点的话就恭喜了。若是继续深问流程,那就须要本身找一些源码来阅读了。

java的多态表如今哪里

主要有两种表现形式:重载和重写

重载:

是发生在同一类中,具备相同的方法名,主要是看参数的个数,类型,顺序不一样实现方法的重载的,返回值的类型能够不一样。

重写:

是发生在两个类中(父类和子类),具备相同的方法名,主要看方法中参数,个数,类型必须相同,返回值的类型必须相同。

    • *

接口有什么用

一、经过接口能够实现不相关类的相同行为,而不须要了解对象所对应的类。

二、经过接口能够指明多个类须要实现的方法。

三、经过接口能够了解对象的交互界面,而不需了解对象所对应的类。

另:Java是单继承,接口可使其实现多继承的功能。

    • *

说说http,https协议

HTTP:

是互联网上应用最为普遍的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可使浏览器更加高效,使网络传输减小。

HTTPS:

是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,所以加密的详细内容就须要SSL。

区别:

一、https协议须要到ca申请证书,通常免费证书较少,于是须要必定费用。

二、http是超文本传输协议,信息是明文传输,https则是具备安全性的ssl加密传输协议。

三、http和https使用的是彻底不一样的链接方式,用的端口也不同,前者是80,后者是443。

四、http的链接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

    • *

说说tcp/ip协议族

TCP/IP协议族是一个四层协议系统,自底而上分别是数据链路层、网络层、传输层和应用层。每一层完成不一样的功能,且经过若干协议来实现,上层协议使用下层协议提供的服务。

一、数据链路层负责帧数据的传递。

二、网络层责数据怎样传递过去。

三、传输层负责传输数据的控制(准确性、安全性)

四、应用层负责数据的展现和获取。

    • *

tcp五层网络协议

物理层:

为数据端设备提供传送数据的通路,数据通路能够是一个物理媒体,也能够是多个物理媒体链接而成。

数据链路层:

为网络层提供数据传送服务。

网络层:

路由选择和中继、激活,终止网络链接、在一条数据链路上复用多条网络链接,多采起分时复用技术 、差错检测与恢复、排序,流量控制、服务选择、网络管理 。

传输层:

传输层是两台计算机通过网络进行数据通讯时,第一个端到端的层次,具备缓冲做用。

应用层:

应用层向应用程序提供服务

    • *

TCP与UDP的区别

一、基于链接与无链接

二、TCP要求系统资源较多,UDP较少; 

三、UDP程序结构较简单 

四、流模式(TCP)与数据报模式(UDP); 

五、TCP保证数据正确性,UDP可能丢包 

六、TCP保证数据顺序,UDP不保证 

    • *

cookie和session的区别,分布式环境怎么保存用户状态

一、cookie数据存放在客户的浏览器上,session数据放在服务器上。

二、cookie不是很安全,别人能够分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session。

三、session会在必定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用COOKIE。

四、单个cookie保存的数据不能超过4K,不少浏览器都限制一个站点最多保存20个cookie。

分布式环境下的session(举例两种):

服务器session复制

原理:任何一个服务器上的session发生改变(增删改),该节点会把这个 session的全部内容序列化,而后广播给全部其它节点,无论其余服务器需不须要session,以此来保证Session同步。

优势:可容错,各个服务器间session可以实时响应。

缺点:会对网络负荷形成必定压力,若是session量大的话可能会形成网络堵塞,拖慢服务器性能。

session共享机制

使用分布式缓存方案好比memcached、redis,可是要求Memcached或Redis必须是集群。

    • *

GIT和SVN的区别

一、GIT是分布式的,SVN不是。

二、GIT把内容按元数据方式存储,而SVN是按文件。

三、GIT分支和SVN的分支不一样。

四、GIT没有一个全局的版本号,而SVN有。

五、GIT的内容完整性要优于SVN。

(通常问会不会用,知道这些区别貌似也没卵用)

请写一段栈溢出、堆溢出的代码

递归调用能够致使栈溢出
不断建立对象能够致使堆溢出

代码以下:

<pre style="margin: 0px 0px 0px 22px; white-space: pre-wrap; overflow-wrap: break-word; font-size: 12px !important; font-family: &quot;Courier New&quot; !important;">

public class Test { public void testHeap(){ for(;;){

ArrayList list = new ArrayList (2000);  
     }

} int num=1; public void testStack(){

num++; this.testStack();  
} public static void main(String[] args){  
   Test  t = new Test ();  
   t.testHeap();  
   t.testStack();

}
}</pre>

BIO、NIO和AIO的区别

Java BIO : 同步并阻塞,服务器实现模式为一个链接一个线程,即客户端有链接请求时服务器端就须要启动一个线程进行处理,若是这个链接不作任何事情会形成没必要要的线程开销,固然能够经过线程池机制改善。

Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的链接请求都会注册到多路复用器上,多路复用器轮询到链接有I/O请求时才启动一个线程进行处理。

Java AIO: 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。

NIO比BIO的改善之处是把一些无效的链接挡在了启动线程以前,减小了这部分资源的浪费(由于咱们都知道每建立一个线程,就要为这个线程分配必定的内存空间)

AIO比NIO的进一步改善之处是将一些暂时可能无效的请求挡在了启动线程以前,好比在NIO的处理方式中,当一个请求来的话,开启线程进行处理,但这个请求所须要的资源尚未就绪,此时必须等待后端的应用资源,这时线程就被阻塞了。

适用场景分析:

 BIO方式适用于链接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4之前的惟一选择,但程序直观简单易理解,如以前在Apache中使用。

 NIO方式适用于链接数目多且链接比较短(轻操做)的架构,好比聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持,如在 Nginx,Netty中使用。

 AIO方式使用于链接数目多且链接比较长(重操做)的架构,好比相册服务器,充分调用OS参与并发操做,编程比较复杂,JDK7开始支持,在成长中,Netty曾经使用过,后来放弃。

    • *

java中常说的堆和栈,分别是什么数据结构;另外,为何要分为堆和栈来存储数据

栈是一种具备后进先出性质的数据结构,也就是说后存放的先取,先存放的后取。

堆是一种通过排序的树形数据结构,每一个结点都有一个值。一般咱们所说的堆的数据结构,是指二叉堆。堆的特色是根结点的值最小(或最大),且根结点的两个子树也是一个堆。因为堆的这个特性,经常使用来实现优先队列,堆的存取是随意的。

为何要划分堆和栈

一、从软件设计的角度看,栈表明了处理逻辑,而堆表明了数据。这样分开,使得处理逻辑更为清晰。

二、堆与栈的分离,使得堆中的内容能够被多个栈共享。一方面这种共享提供了一种有效的数据交互方式(如:共享内存),另外一方面,堆中的共享常量和缓存能够被全部栈访问,节省了空间。

三、栈由于运行时的须要,好比保存系统运行的上下文,须要进行地址段的划分。因为栈只能向上增加,所以就会限制住栈存储内容的能力。而堆不一样,堆中的对象是能够根据须要动态增加的,所以栈和堆的拆分,使得动态增加成为可能,相应栈中只需记录堆中的一个地址便可。

四、体现了Java面向对象这一核心特色(也能够继续说一些本身的理解)

    • *

为何要用线程池

那先要明白什么是线程池

线程池是指在初始化一个多线程应用程序过程当中建立一个线程集合,而后在须要执行新的任务时重用这些线程而不是新建一个线程。

使用线程池的好处

一、线程池改进了一个应用程序的响应时间。因为线程池中的线程已经准备好且等待被分配任务,应用程序能够直接拿来使用而不用新建一个线程。

二、线程池节省了CLR 为每一个短生存周期任务建立一个完整的线程的开销并能够在任务完成后回收资源。

三、线程池根据当前在系统中运行的进程来优化线程时间片。

四、线程池容许咱们开启多个任务而不用为每一个线程设置属性。

五、线程池容许咱们为正在执行的任务的程序参数传递一个包含状态信息的对象引用。

六、线程池能够用来解决处理一个特定请求最大线程数量限制问题。

    • *

msyql优化经验

一、对查询进行优化,应尽可能避免全表扫描,首先应考虑在 where 及 order by 涉及的列上创建索引。

二、应尽可能避免在 where 子句中使用!=或<>操做符,不然引擎将放弃使用索引而进行全表扫描。

三、尽可能使用数字型字段,若只含数值信息的字段尽可能不要设计为字符型,这会下降查询和链接的性能,并会增长存储开销。这是由于引擎在处理查询和链接时会逐个比较字符串中每个字符,而对于数字型而言只须要比较一次就够了。

四、任何地方都不要使用 select from t ,用具体的字段列表代替“”,不要返回用不到的任何字段。

五、避免频繁建立和删除临时表,以减小系统表资源的消耗。诸如此类,等等等等......

悲观锁和乐观锁的区别,怎么实现

悲观锁:一段执行逻辑加上悲观锁,不一样线程同时执行时,只能有一个线程执行,其余的线程在入口处等待,直到锁被释放。

乐观锁:一段执行逻辑加上乐观锁,不一样线程同时执行时,能够同时进入执行,在最后更新数据的时候要检查这些数据是否被其余线程修改了(版本和执行初是否相同),没有修改则进行更新,不然放弃本次操做。

悲观锁的实现:

//0.开始事务`
begin``;/``begin` `work``;/start ``transaction``; (三者选一就能够)`
//1.查询出商品信息`
select` `status ``from` `t_goods ``where` `id=1 ``for` `update``;`
//2.根据商品信息生成订单`
insert` `into` `t_orders (id,goods_id) ``values` `(``null``,1);`
//3.修改商品status为2`
update` `t_goods ``set` `status=2;`
//4.提交事务`
commit``;/``commit` `work``;`

乐观锁的实现:

1.查询出商品信息`
select` `(status,status,version) ``from` `t_goods ``where` `id=#{id}`
2.根据商品信息生成订单`
3.修改商品status为2`
update` `t_goods`
set` `status=2,version=version+1`
where` `id=#{id} ``and` `version=#{version};`
相关文章
相关标签/搜索