面试问题整理

Java Web

转发和重定向的区别

  1. 转发是服务器行为,重定向是客户端行为
  2. 转发速度快,重定向速度慢
  3. 转发的是同一次请求,重定向是两次不同的请求
  4. 转发不会执行转发后的代码,重定向会执行重定向之后的代码
  5. 转发地址栏没有变化,重定向地址栏有变化
  6. 转发必须在同一台服务器下完成,重定向可以不同的服务器下完成

在servlet中调用转发,重定向语句:
request.getRequestDispatcher(“new.jsp”).forward(request,response); //转发
response.sendRedirect(“new.jsp”); //重定向

转发过程
客户浏览器发送http请求,web服务器接收请求,调用内部的一个方法在容器内完成请求处理和转发动作,将目标资源发送给客户;此处,转发的路径必须是同一个web服务器下的url,不能转向其他的web路径上去,中间传递的是自己的容器内request。在客户浏览器路径显示的仍然是其第一次访问的路径,客户端并不能感受到服务器做了转发。转发行为是浏览器只做了一次请求。

重定向过程
客户浏览器发送http请求,web服务器接收后发送302状态码及新的location给客户端浏览器,客户浏览器根据302响应会自动再次发送一个新的http请求,请求url是新的location地址,服务器根据此请求寻找资源发送给客户。此处的location可以是任意的url,既然是新的请求,也就没有request的传递概念了。在客户浏览器地址栏显示的是重定向的路径,客户可以观察到地址的变化。重定向行为是浏览器至少做了两次请求访问的,即两次request。

HTTP

HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web)服务器传输超文本到本地浏览器的传送协议

HTTP是一个基于TCP/IP通信协议来传递数据(HTML文件,图片,查询结果等)

HTTP是属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。

HTTP协议工作与客户端-服务器架构上。浏览器作为HTTP客户端通过URL向HTTP服务器(WEB服务器)发送请求。WEB服务器根据接收到的请求后,向客户端发送响应消息。

Java SE

varchar和char的区别

  1. 定长和变长
    char表示固定长度,varchar表示可变长度。char如果插入的长度小于定义长度时,使用空格填充;varchar小于定义长度时,还是按实际长度存储,插入多长就存多长。
    因为char长度固定,char的存取速度要比varchar快的多,方便程序的存储与查找;但是char也为此付出空间的代价,长度固定,会占据更多的空间,以空间换取时间效率。varchar刚好相反,以时间换空间。
  2. 存储的容量不同
    varchar(M)和char(M),M都表示字符数。varchar的最大长度是65536个字节(utf编码下字符长度为21845),不同的编码所对应的最大可存储的字符数不同。char最多可存储255个字符,不同的编码所对应的最大可用字节数不同。

ArrayList的底层原理

ArrayList的底层数据结构就是一个数组,数组元素类型为Object类型,对ArrayList的所有操作底层都是基于数组的。

ArrayList的线程安全
对ArrayList进行添加元素的操作的时候是分两个步骤完成的,即第一步现在object[size]的位置上存放需要添加的元素;第二步将size的值增加1。由于整个过程在多线程的环境下不能保证具有原子性,因此ArrayList在多线程环境下是线程不安全的。
如果非要在多线程环境使用ArrayList,就需要保证他的线程安全性,通常两种解决办法。

  1. 使用synchronized关键字
  2. 使用Collections类中的静态方法synchronizedList()对ArrayList调用即可

ArrayList扩容机制
自己查看ArrayList类的add()方法去,数组扩容按照当前容量的1.5倍进行扩容。

HashMap 和 HashTable

HashMap
HashMap是基于哈希表的map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null键和null值,此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。HashMap的底层就是一个数组结构,数组中的每一项又是一个链表。当新建一个HashMap的时候,就会初始化一个数组。
将键值对传递给put()时,它调用健对象的hashCode()方法来计算hashcode,然后找到bucket位置来存储对象。当获取对象时,通过对象的equals()方法找到正确的键值对,然后返回值对象。HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会存在链表的下一个节点中。HashMap在每个链表节点中存储键值对对象。当两个不同的键对象的hashcode相同时会发生什么?他们会存储在同一个bucket位置的链表中。
在这里插入图片描述
HashTable
和HashMap一样,HashTable也是一个散列列表,他存储的内容是键值对映射。HashTable继承于DIctionary类,实现了Map、Cloneable、Serializable接口。HashTable的函数都是同步的,这意味着他是线程安全的。他的key,value都不能为null。
HashTable容器使用synchronized来保证线程安全,但在多线程环境下HashTable的效率非常低。因为当一个线程访问HashTable的同步方法时,其他线程访问HashTable的同步方法时,就可能会进入阻塞或轮询状态。这就导致所有访问HashTable的线程都必须竞争同一把锁。

ConcurrentHashMap
底层采用分段的数组+链表实现,线程安全的。
ConcurrentHashMap采用锁分段技术,首先将数据分成一段一段的存储,然后给每段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他数据段的数据也能被其他线程访问。

HashMap 和 HashTable 的区别

  1. HashTable是线程安全的,而HashMap则非线程安全
  2. HashMap可以使用 null 作为 key ,而 HashTable 则不允许 null 最为 key
  3. HashMap 是对 Map 接口的实现,而HashTable实现了Map接口和DIctionary抽象类
  4. HashMap的初始容量为16,HashTable的初始容量为11,两者的填充因子默认都是0.75
  5. 两者计算hash的方法不同

字符串的拼接方式

  1. 使用“+”拼接字符串
  2. 使用String类中的方法concat方法
  3. StringBuffer
    就是为了解决大量拼接字符串时产生很多中间对象而提供的一个类,提供append和add方法,可以将字符串添加到已有的序列的末尾或指定位置,本质是一个线程安全的可修改的字符序列,把所有修改数据的方法都加上了synchronized关键字,保证了线程的安全但是需要付出性能的代价。
  4. StringBuilder
    StringBuilder和StringBuffer本质上没什么区别,就是去掉了保证线程安全的那部分,减少了开销。
  5. StringUtils.join

equals方法的四个特性

  1. 自反性(reflexive)
    对于任何非null的引用值x,x.equals(x)必须返回True
  2. 对称性
    对于任何非null的引用值x,y,当且仅当y.equals(x)返回True时,x.equals(y) 返回True
  3. 传递性
    对于任何非null的引用值x,y,z,如果x.equals(y)返回True,y.equals(z)返回True,则x.equals(z)返回True
  4. 一致性
    对于任何非null的引用值x,y,只要equals的比较操作在对象中所用的信息没有被修改,多次调用x.equals(y)就会一致地返回True,或者一致的返回False

Exception和Error

Exception和Error都继承了Throwable类,在Java中只有Throwable类型的实例才可以被抛出或者捕获,他是异常处理机制的基本类型。

Exception(异常)表示程序可以处理的异常,可以捕获且可能恢复,是程序本身可以处理的异常。遇到这类异常,应该尽可能处理异常,使程序恢复运行。

Error(错误)是系统中的错误,程序员不能改变和处理的,实在程序编译时出现的错误,只能通过修改程序才能修正。一般值与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。

Exception又分为CheckedException和UnCheckedException。
  CheckedException(编译时异常):需要使用try–catch显示的捕获,对于可恢复的异常使用
  UnCheckedException(RuntimeException运行时异常):不需要捕获

数据库

数据库索引

缺点

  1. 虽然索引大大提高了查询速度,同时会降低更新表的速度。如insert,update,delete。因为更新表示,不仅要保存数据,还要保存索引。
  2. 建立索引会占用磁盘空间的索引文件。

注意事项

  1. 索引不会包含有null值的列。
    只要列中包含null值都将不会被包含在索引中,复合索引中只要有一列含有null值,那么这一列对于此复合索引就是无效的。所以在数据库设计时不要让字段默认值为null。
  2. 使用短索引。
    对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个char(255)的列,如果在前10或20个字符串内,多数值是唯一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘I/O操作。
  3. 索引列排序
    查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库的默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。
  4. like语句
    一般情况下不推荐使用like操作,如果非使用不可,如何使用也是个问题。like "%aaa%"不会使用索引,而like "aaa%"可以使用索引。
  5. 不要再列上进行运算,这将导致索引失效而进行全表扫描
  6. 不适用not in 和 <> 操作

联合索引
对多个字段同时建立索引(有顺序,ABC和ACB是两个完全不同的联合索引)。以联合索引(a,b,c)为例:

  1. 此联合索引相当于建立了a、ab、abc三个索引。
  2. 覆盖(动词)索引。
    同样的有联合索引(a,b,c),如果有如下的sql: select a,b,c from table where a=xxx and b = xxx。那么MySQL可以直接通过遍历索引取得数据,而无需读表,这减少了很多的随机io操作。减少io操作,特别的随机io其实是dba主要的优化策略。所以,在真正的实际应用中,覆盖索引是主要的提升性能的优化手段之一。
  3. 索引列越多,通过索引筛选出的数据越少。
    有1000W条数据的表,有如下sql:select * from table where a = 1 and b =2 and c = 3,假设每个条件可以筛选出10%的数据,如果只有单值索引,那么通过该索引能筛选出1000W*10%=100w 条数据,然后再回表从100w条数据中找到符合b=2 and c= 3的数据,然后再排序,再分页;如果是复合索引,通过索引筛选出1000w *10% *10% *10%=1w,然后再排序、分页,哪个更高效,一眼便知。
  • 单个索引需要注意的事项,组合索引全部通用。比如索引列不要参与计算啊、or的两侧要么都索引列,要么都不是索引列啊、模糊匹配的时候%不要在头部啦等等
  • 最左匹配原则。(A,B,C) 这样3列,mysql会首先匹配A,然后再B,C。如果用(B,C)这样的数据来检索的话,就会找不到A使得索引失效。如果使用(A,C)这样的数据来检索的话,就会先找到所有A的值然后匹配C,此时联合索引是失效的。
  • 把最常用的,筛选数据最多的字段放在左侧

IN 和 EXISTS 的区别

  1. in() 适合B表比A表数据少的情况
  2. exists()适合B表比A表数据多的情况
  3. 当A表数据和B表数据一样情况下,in和exists的效率差不多
  4. 使用 not in 和 not exists ,则直接使用 not exits,因为 not in 会全表扫描,不走索引,not exists会走索引。

select * from A where id in( select id from B )
sql语句先执行子查询,即查询B表,再查A表。in()只执行一次,它查出B表中的所有id字段并缓存起来(内存中),之后检查A表的id是否与B表中的id相等,如果相等则将A表的记录加入结果集中,直到遍历完A表的所有记录。最多可能遍历 A.length * B.length 次(内存中)。
select a.* from A a where exists ( select 1 from B b where a.id=b.id )
先对where 前的主查询(A表)进行查询,然后用主查询的结果一个一个的代入exists的查询进行判断,如果为真则输出
当前这一条主查询的结果,否则不输出。 会执行 A.length 次判断A表中的id是否与B表中的id相等(查询数据库)。

行转列、列转行

图一:
在这里插入图片描述
图二:
在这里插入图片描述
行转列 case when 方式:

SELECT
	user_name,
	max( CASE `subject` WHEN '语文' THEN score ELSE 0 END ) AS '语文',
	max( CASE `subject` WHEN '数学' THEN score ELSE 0 END ) AS '数学',
	max( CASE `subject` WHEN '英语' THEN score ELSE 0 END ) AS '英语',
	max( CASE `subject` WHEN '生物' THEN score ELSE 0 END ) AS '生物' 
FROM
	student_scores 
GROUP BY
	user_name;

多线程

多线程间的通信方式

  1. 使用synchronized关键字同步实现多线程间的通信
    这种方式,本质上是“共享内存”的概念。多个线程需要访问同一个共享变量,谁拿到了锁(获得访问权限),谁就可以执行。
  2. 线程while轮询
  3. wait/notify 机制(通知/等待)

spring

spring bean生命周期

  1. 实例化  Instantiation
  2. 属性赋值  Populate
  3. 初始化  Initialization
  4. 销毁  Destruction

DipatcherServlet作用

  1. 客户端发出一个http请求给web服务器,web服务器对http请求进行解析,如果匹配DispatcherServlet的请求映射路径(在web.xml中指定),web容器将请求转交给DispatcherServlet.
  2. DipatcherServlet接收到这个请求之后将根据请求的信息(包括URL、Http方法、请求报文头和请求参数Cookie等)以及HandlerMapping的配置找到处理请求的处理器(Handler)。
  3. DispatcherServlet根据HandlerMapping找到对应的Handler,将处理权交给Handler(Handler将具体的处理进行封装),再由具体的HandlerAdapter对Handler进行具体的调用。
  4. Handler对数据处理完成以后将返回一个ModelAndView()对象给DispatcherServlet。
  5. Handler返回的ModelAndView()只是一个逻辑视图并不是一个正式的视图,DispatcherSevlet通过ViewResolver将逻辑视图转化为真正的视图View。
  6. Dispatcher通过model解析出ModelAndView()中的参数进行解析最终展现出完整的view并返回给客户端。

对Spring中IOC和AOP的理解

IOC:控制反转;DI:依赖注入。是同一种概念,利用了工厂模式。spring中创建被调用者的工作不再由调用者来完成,而是由spring容器管理,因此称为控制反转。
  1. 让spring来管理对象的创建及管理对象
  2. 在spring容器启动的时候,spring会把配置文件中配置的bean都初始化好
  3. 需要调用的时候,容器把已经初始化好的bean分配给需要调用这些bean的类。
  4. spring以动态灵活的方式来管理对象,注入的方式有两种,设置注入和依赖注入
  
AOP:面向切面编程。完善依赖注入,主要表现为:
  1. 面向切面编程提供声明式事务管理
  2. spring支持用户自定义切面
面向切面编程(AOP)是面向对象编程(OOP)的补充,面向对象编程将程序分解成各个层次的对象,面向切面编程将程序运行分解成各个切面。AOP从程序运行角度考虑程序的结构,提取业务处理过程的切面,OOP是静态的抽象,AOP是动态的抽象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值