java常见面试题
1.= = 和equals区别
==号和equals()方法都是比较是否相等的方法,==号在比较基本数据类型时比较的是值,而用==号比较两个对象时比较的是两个对象的地址值
2.list中常见的arraylist linkedlist 区别
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
Map
├Hashtable
├HashMap
└WeakHashMap
1、ArrayList和LinkedList可想从名字分析,它们一个是Array(动态数组)的数据结构,一个是Link(链表)的数据结构,此外,它们两个都是对List接口的实现。
前者是数组队列,相当于动态数组;后者为双向链表结构,也可当作堆栈、队列、双端队列
2、当随机访问List时(get和set操作),ArrayList比LinkedList的效率更高,因为LinkedList是线性的数据存储方式,所以需要移动指针从前往后依次查找。
3、当对数据进行增加和删除的操作时(add和remove操作),LinkedList比ArrayList的效率更高,因为ArrayList是数组,所以在其中进行增删操作时,会对操作点之后所有数据的下标索引造成影响,需要进行数据的移动。
4、从利用效率来看,ArrayList*性较低,因为它需要手动的设置固定大小的容量,但是它的使用比较方便,只需要创建,然后添加数据,通过调用下标进行使用;而LinkedList*性较高,能够动态的随数据量的变化而变化,但是它不便于使用。
5、ArrayList主要控件开销在于需要在lList列表预留一定空间;而LinkList主要控件开销在于需要存储结点信息以及结点指针信息。
(动态数组查询快,双向链表添加删除快,从而有了hashmap---)
Java中的数据存储方式有两种结构,一种是数组,另一种就是链表,前者的特点是连续空间,寻址迅速,但是在增删元素的时候会有较大幅度的移动,所以数组的特点是查询速度快,增删较慢。
而链表由于空间不连续,寻址困难,增删元素只需修改指针,所以链表的特点是查询速度慢、增删快。
那么有没有一种数据结构来综合一下数组和链表以便发挥他们各自的优势?答案就是哈希表。
3. hashmap hashtable concurrenthashmap
HashMap和HashTable的区别一种比较简单的回答是:
(1)HashMap是非线程安全的,HashTable是线程安全的。
(2)HashMap的键和值都允许有null存在,而HashTable则都不行。
(3)因为线程安全、哈希效率的问题,HashMap效率比HashTable的要高。
HashTable和ConCurrentHashMap的对比
先对ConcurrentHashMap进行一些介绍吧,它是线程安全的HashMap的实现。
HashTable里使用的是synchronized关键字,这其实是对对象加锁,锁住的都是对象整体,当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时间。
ConcurrentHashMap引入了分割(Segment),上面代码中的最后一行其实就可以理解为把一个大的Map拆分成N个小的HashTable,在put方法中,会根据hash(paramK.hashCode())来决定具体存放进哪个Segment,如果查看Segment的put操作,我们会发现内部使用的同步机制是基于lock操作的,这样就可以对Map的一部分(Segment)进行上锁,这样影响的只是将要放入同一个Segment的元素的put操作,保证同步的时候,锁住的不是整个Map(HashTable就是这么做的),相对于HashTable提高了多线程环境下的性能,因此HashTable已经被淘汰了。
1)ConcurrentHashMap对整个桶数组进行了分割分段(Segment),然后在每一个分段上都用lock锁进行保护,相对于HashTable的syn关键字锁的粒度更精细了一些,并发性能更好,而HashMap没有锁机制,不是线程安全的。
(2)HashMap的键值对允许有null,但是ConCurrentHashMap都不允许。
4.多线程
创建线程的方式
比较常见的一个问题了,一般就是两种:
(1)继承Thread类
(2)实现Runnable接口
至于哪个好,不用说肯定是后者好,因为实现接口的方式比继承类的方式更灵活,也能减少程序之间的耦合度, 面向接口编程 也是设计模式6大原则的核心。
start()方法和run()方法的区别
只有调用了start()方法,才会表现出多线程的特性,不同线程的run()方法里面的代码交替执行。如果只是调用run()方法,那么代码还是同步执行的,必须等待一个线程的run()方法里面的代码全部执行完毕之后,另外一个线程才可以执行其run()方法里面的代码。
Runnable接口和Callable接口的区别
Runnable接口中的run()方法的返回值是void,它做的事情只是纯粹地去执行run()方法中的代码而已;Callable接口中的call()方法是有返回值的,是一个泛型,和Future、FutureTask配合可以用来获取异步执行的结果。
这其实是很有用的一个特性,因为 多线程相比单线程更难、更复杂的一个重要原因就是因为多线程充满着未知性 ,某条线程是否执行了?某条线程执行了多久?某条线程执行的时候我们期望的数据是否已经赋值完毕?无法得知,我们能做的只是等待这条多线程的任务执行完毕而已。而Callable+Future/FutureTask却可以获取多线程运行的结果,可以在等待时间太长没获取到需要的数据的情况下取消该线程的任务,真的是非常有用。
sleep方法和wait方法有什么区别
这个问题常问,sleep方法和wait方法都可以用来放弃CPU一定的时间,不同点在于如果线程持有某个对象的监视器,sleep方法不会放弃这个对象的监视器,wait方法会放弃这个对象的监视器
sleep()方法是让“正在执行的线程”休眠,这个“正在执行的线程”是指this.currentThread()返回的线程。
为什么wait()方法和notify()/notifyAll()方法要在同步块中被调用
这是JDK强制的,wait()方法和notify()/notifyAll()方法在调用前都必须先获得对象的锁
wait()方法和notify()/notifyAll()方法在放弃对象监视器时有什么区别
wait()方法和notify()/notifyAll()方法在放弃对象监视器的时候的区别在于: wait()方法立即释放对象监视器,notify()/notifyAll()方法则会等待线程剩余代码执行完毕才会放弃对象监视器 。
为什么要使用线程池
避免频繁地创建和销毁线程,达到线程对象的重用。另外,使用线程池还可以根据项目灵活地控制并发的数目。
怎么唤醒一个阻塞的线程
如果线程是因为调用了wait()、sleep()或者join()方法而导致的阻塞,可以中断线程,并且通过抛出InterruptedException来唤醒它;如果线程遇到了IO阻塞,无能为力,因为IO是操作系统实现的,Java代码并没有办法直接接触到操作系统
sychronized锁 lock
ReentrantLock 拥有Synchronized相同的并发性和内存语义,此外还多了 锁投票,定时锁等候和中断锁等候
线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定,
如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断
如果 使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情
在并发量比较小的情况下,使用synchronized是个不错的选择,但是在并发量比较高的情况下,其性能下降很严重,此时ReentrantLock是个不错的方案
Struts2和SpringMVC的执行流程
先介绍一下SpringMVC的执行流程:
1:客户端发起请求到DispatcherServlet(前端控制器)
2:前端控制器请求HandlerMapping(处理器映射器)查找 Handler
根据xml配置、注解进行查找
3:HandlerMapping(处理器映射器)向DispatcherServlet(前端控制器)返回Handler
4:DispatcherServlet(前端控制器)调用HandlerAdapter(处理器适配器)去执行Handler
5:HandlerAdapter(处理器适配器)去执行Handler
6:Handler执行完成给HandlerAdapter(处理器适配器)返回ModelAndView
7:HandlerAdapter(处理器适配器)向前端控制器返回ModelAndView
ModelAndView是springmvc框架的一个底层对象,包括 Model和view
8:前端控制器请求ResolverView(视图解析器)去进行视图解析
根据逻辑视图名解析成真正的视图(jsp)
9:ResolverView(视图解析器)向DispatcherServlet(前端控制器)返回View
10:DispatcherServlet(前端控制器)进行视图渲染
视图渲染将模型数据(在ModelAndView对象中)填充到request域
最后DispatcherServlet(前端控制器)向用户响应(response)结果
然后是Struts2的执行流程:1、客户端向服务器端发送一个请求,经过一系列的过滤器(在Struts2.0版本的时候叫做FilterDispatcher,在Struts2.1以上的版本叫做StrutsPrepareAndExecuteFilter),过滤器(StrutsPrepareAndExecuteFilter)会解析Struts.xml文件,请求查找相应的Action,如果没有则会报错,如果有则会生成对应的代理对象,然后经过一系列的拦截器,直到调用Action类中的execute()方法,处理结果由Struts2的处理器到核心过滤器再到服务器,最后由服务器响应(Response)到客户端。
spring的理解
https://www.zhihu.com/question/48427693?sort=created
https://www.zhihu.com/question/23277575
Spring的事务
https://www.cnblogs.com/wangyayun/p/6530189.html
mybatis返回主键
https://blog.csdn.net/wuseyukui/article/details/52390076
jsp内置对象 ,request、response、session、application、out、pagecontext、config、
java request.forward和response.redirect 区别
1: request.getRequestDispatcher("/other/page.html?para=some").forward(ServletRequest, ServletResponse);
用于将请求在服务器端重定向至另一个页面,它会保留request里面的参数、状态等,而且客户端并不知道请求被重定向。
2: response.sendRedirect(request.getContextPath() + "/index.html");
用于告诉客户端重新发送请求至新的页面,两次请求独立,除了能在url上挂参数外,由于是两次独立请求,request和response也是独立的,如下图:
java8个基本数据类型,int long char short byte double float boolean
js标签选择器取值,#id .class input[name='']
spring注解
@Autowired Qualifier(一个interface有多个impl时,指定注入Bean的名称),Resource,Service,
@Repository对应数据访问层Bean
设计模式 单列 工厂方法 简单工厂 适配器 代理 模板方法 都是spring用到的 如beanfactory JdbcTemplate,aop中的Adapter是适配器