欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

经典面试题(Java)

程序员文章站 2022-05-05 22:00:38
...

1、Spring的优点:

  1. 非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API
  2. 依赖注入:DI——Dependency Injection,反转控制(IOC)最经典的实现。
  3. 面向切面编程:Aspect Oriented Programming——AOP
  4. 容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期
  5. 组件化:Spring实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以 使用XML和Java注解组合这些对象。
    一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上Spring 自身也提供了表述层的SpringMVC和持久层的Spring JDBC)。

2、 什么是ioc 什么是依赖注入

  • Ioc:inversion of control 控制反转 我们不再手动创建对象 而是将对象的创建权交给IOC容器,需要获取对象时直接从IOC容器中获取

  • DI:dependency injection 依赖注入 IOC的另一种表述方式:即组件以一些预先定义好的方式(例如:setter 方法)接受来自于容器的资源注入。

  • IOC开发中怎么实现?两种方式:xml 注解
    通过配置Spring.xml文件 或者使用注解

  • ioc XML文件实现方式,注解实现方式

    • 在spring.xml文件里 写一个组件并为其赋值 然后在需要的地方 通过实例化IOC容器 根据组件对应的类型或id值 从容器中提取 ClassPathXmlApplicationContext
    • 使用注解,需要先在web.xml文件中配置监听器ContextLoaderListener 再在dao层使用注解@Reponsitory service层加注解@Service WEB层加注解@Controller 需要使用对象的时候 使用@Autowired注解 这样IOC容器就会自动创建好这个对象

3、请描述Spring MVC的工作流程?描述一下 DispatcherServlet 的工作流程?

  1. 用户发送请求至前端控制器DispatcherServlet;
  2. DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
  3. 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;
  4. DispatcherServlet 调用 HandlerAdapter处理器适配器;
  5. HandlerAdapter经过适配调用 具体处理器(Handler,也叫后端控制器); (6)Handler执行完成返回ModelAndView;
  6. HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
  7. DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
  8. ViewResolver解析后返回具体View;
  9. DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
  10. DispatcherServlet响应用户。
    经典面试题(Java)

4、Spring MVC的控制器是不是单例模式,如果是,有什么问题,怎么解决?

答:是单例模式,所以在多线程访问的时候有线程安全问题,不要用同步,会影响性能的,解决方案是在控制器里面不能写字段。

5、常用注解

注解原理是什么
注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。我们通过反射获取注解时,返回的是Java运行时生成的动态代理对象。通过代理对象调用自定义注解的方法,会最终调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值。而memberValues的来源是Java常量池。

Spring MVC常用的注解有哪些?

  • @RequestMapping:用于处理请求 url,映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径。
  • @RequestBody:注解实现接收http请求的json数据,将json转换为java对象。
  • @ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。

6、Spring MVC怎么和AJAX相互调用的?

通过Jackson框架就可以把Java里面的对象直接转化成Js可以识别的Json对象。具体步骤如下 :

(1)加入Jackson.jar
(2)在配置文件中配置json的映射
(3)在接受Ajax方法里面可以直接返回Object,List等,但方法前面要加上@ResponseBody注解。

7、springmvc如何处理异常

三种方法

  1. 在本类中:在方法上使用@ExceptionHandler 声明属性value={具体的异常类.class}如果不知道是什么类型的可以写成Exception e 因为Exception是所有异常类的父类,但是如果有精确处理,会优先走精确处理
  2. 外部处理类来处理异常 关键注解:@ControllerAdvice 在方法上使用@ExceptionHandler 声明属性value={具体的异常类.class}
  3. 在springmvc中配置异常处理解析器
  4. 若想将错误信息显示在页面上 可以使用ModelAndView模型对象 将错误信息存入其中
    异常处理的优先级别:本类>外部处理类>配置文件
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
	<property name="exceptionMappings">
		<props>
			<prop key="java.lang.ArithmeticException">error2</prop>
			<prop key="java.lang.NullPointerException">error2</prop>
		</props>
	</property>
</bean>

8、SpringMVC怎么样设定重定向和转发的?

  • 转发:在返回值前面加"forward:",比如"forward:user.go?name=1"
  • 重定向:在返回值前面加"redirect:",比如"redirect:user.go"

9、SpingMVC中函数的返回值是什么?

  • 返回值可以有很多类型,有String,ModelAndView。
    ModelAndView类把视图和数据都合并的一起的,但一般用String比较好

10、SpringMvc中有个类把视图和数据都合并的一起的,叫什么?

  • ModelAndView

11、什么是SpringMVC restful风格,如何在spring mvc实现RESTful 服务

RESTful是一种架构的规范与约束、原则,符合这种规范的架构就是RESTful架构 在RESTful接口中,所有的方法都是返回JSON,没有返回页面的(ModelAndView),因此,所有的方法上都需要添加

  • @ResponseBody注解。
  • 一个替代的简化方案,是使用 @RestController 代替@Controller。@RestController实际上是一个组合注解,是@Controller和@ResponseBody的组合:
  • 导入jackson2包
  • 开启注解驱动mvc:annotation-driven/

12、springMVC和struts2的区别有哪些?

  • springmvc的入口是一个servlet即前端控制器(DispatchServlet)struts2入口是一个filter过滤器(StrutsPrepareAndExecuteFilter)。
  • springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例)
    struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。C.springmvc通过参数解析器将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过reques域传输到页面,Jsp视图解析器默认使用jstl
    Struts采用值栈存储请求和响应的数据,通过OGNL存取数据。

13、spring的aop:

AOP(这里的AOP指的是面向切面编程思想,而不是Spring AOP)主要的的实现技术主要有Spring AOP和AspectJ。

  1. AspectJ的底层技术。

    AspectJ的底层技术是静态代理,即用一种AspectJ支持的特定语言编写切面,通过一个命令来编译,生成一个新的代理类,该代理类增强了业务类,这是在编译时增强,相对于下面说的运行时增强,编译时增强的性能更好。

  2. Spring AOP
    Spring AOP采用的是动态代理,在运行期间对业务方法进行增强,所以不会生成新类,对于动态代理技术,Spring AOP提供了对JDK动态代理的支持以及CGLib的支持。
    JDK动态代理只能为接口创建动态代理实例,而不能对类创建动态代理。需要获得被目标类的接口信息(应用Java的反射技术),生成一个实现了代理接口的动态代理类(字节码),再通过反射机制获得动态代理类的构造函数,利用构造函数生成动态代理类的实例对象,在调用具体方法前调用invokeHandler方法来处理。
    CGLib动态代理需要依赖asm包,把被代理对象类的class文件加载进来,修改其字节码生成子类。但是Spring AOP基于注解配置的情况下,需要依赖于AspectJ包的标准注解,但是不需要额外的编译以及AspectJ的织入器,而基于XML配置不需要。

14、@Resource和@AutoWire有什么区别?

  1. @AutoWire默认按类型装配,默认情况下要求依赖对象必须存在,如果允许为空就设置required属性为false。
  2. @resource默认按名称去装配,当找不到与名称匹配的Bean时才按照类型去装配。
  3. @resource注解来源为JDK,其属性为name,type,而@autoWire来源于Spring,其属性为required
  4. @Resource装配顺序
    (1). 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
    (2). 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
    (3). 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
    (4). 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;
    另外,由于@Autowired是按照类型进行装配的 所以可以用集合去接收,
    比如
    @Autowired
    Collection xxs;//BaseXxx可为接口或父类,装配的为全部的实现类或子类

15、java中常用注解都有哪些,都代表什么意思?

spring中常用注解:

  1. @Serice 业务层,给类起一个别名,方便注入到其它类当中
  2. @Controlle 控制层,,于标记在一个类上,使用它标记的类就是一个SpringMVC Controller对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping注解。@Controller只是定义了一个控制器类,而使用@RequestMapping注解的方法才是真正处理请求的处理器。
  3. @RequestMapping 是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
  4. @RestController 和Controller注解是一样的,唯一不同就是返回的数据格式类型以Json返回,它是@aaa@qq.com两个注解的结合。
  5. @ResponseBody注解的作用是以json数据格式进行返回。
  6. @PathVariable注解是用来获取请求uri中,变量的值。
  7. @RequesParam注解可以对传入参数指定参数名。
  8. @Resource注解和@AutoWire注解 都是注入,把声明的类注入到当前类中 不需要再new,即可使用声明类中的方法。

springboot中常用注解:

@SpringbootApplication中包含三个注解

  • @SpringBootConfiguration注解: 这个注解的作用就是声明当前类是一个配置类,然后Spring会自动扫描到添加了@Configuration的类,读取其中的配置信息,而@SpringBootConfiguration是来声明当前类是SpringBoot应用的配置类,项目中只能有一个。所以一般我们无需自己添加。
  • @EnableAutoConfiguration注解: 开启自动配置,告诉SpringBoot基于所添加的依赖,去“猜测”你想要如何配置Spring。比如我们引入了spring-boot-starter-web,而这个启动器中帮我们添加了tomcat、SpringMVC的依赖,此时自动配置就知道你是要开发一个web应用,所以就帮你完成了web及SpringMVC的默认配置了!我们使用SpringBoot构建一个项目,只需要引入所需框架的依赖,配置就可以交给SpringBoot处理了。
  • @ComponentScan注解: 配置组件扫描的指令,提供了类似与context:component-scan标签的作用,通过basePackageClasses或者basePackages属性来指定要扫描的包。如果没有指定这些属性,那么将从声明这个注解的类所在的包开始,扫描包及子包,而我们的@SpringBootApplication注解声明的类就是main函数所在的启动类,因此扫描的包是该类所在包及其子包。因此,一般启动类会放在一个比较前的包目录中。

16、多线程有几种实现方法?有什么区别?

实现方法:

  1. 1.继承Thread类
  2. 实现Runnable接口(Callable接口) 一个类如果实现了Runnable接口或者继承了Thread类,那么它就是一个多线程类,如果是要实现多线程,还需要重写run()方法,所以run() 方法是多线程的入口。

多线程的两种实现方式的区别:

  • Thread是Runnable接口的子类,实现Runnable接口的方式解决了Java单继承的局限
    Runnable接口实现多线程比继承Thread类更加能描述数据共享的概念

同步的实现方面有两种,分别是synchronized,wait与notify

  • wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
  • sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉 InterruptedException异常。
  • notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
  • Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

产生死锁的四个必要条件:

  1. 互斥条件:一个资源每次只能被一个进程使用。
  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  3. 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

如何避免死锁?
上面列出了死锁的四个必要条件,我们只要想办法破其中的任意一个或多个条件,就可以避免死锁发生,一般有以下几种方法:

  1. 按同一顺序访问对象。
  2. 避免事务中的用户交互。
  3. 保持事务简短并处于一个批处理中。
  4. 使用较低的隔离级别。
  5. 使用基于行版本控制的隔离级别。
  6. 使用绑定连接。

17、#{} 和 ${}的区别?

#{}表示一个占位符号

  • 通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc
    类型转换,#{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType
    传输单个简单类型值,#{}括号中可以是 value 或其它名称。

${}表示拼接 sql 串

  • 通过${}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换,
    可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,{}可以接收简单类型值或 pojo 属性值,如果parameterType传输单个简单类型值,可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,{}括号中只能是 value。

18、重定向和转发的异同?

  1. 重定向是两次请求,转发是一次请求,因此转发的速度要快于重定向
  2. 重定向之后地址栏上的地址会发生变化,变化成第二次请求的地址,转发之后地址栏上的地址不会变化,还是第一次请求的地址
  3. 转发是服务器行为,重定向是客户端行为。
  4. 重定向时的网址可以是任何网址,转发的网址必须是本站点的网址。

19、cookie和session的区别?

  1. 数据存放位置不同:
    cookie数据存放在客户的浏览器上,session数据放在服务器上。
  2. 安全程度不同:
    cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session。
  3. 性能使用程度不同:
    session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。数据存储
  4. 大小不同:
    单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie,而session则存储与服务端,浏览器对其没有限制。

20、get和post请求的区别?

  1. Get是不安全的,因为在传输过程,数据被放在请求的URL中;Post的所有操作对用户来说都是不可见的。
  2. Get传送的数据量较小,这主要是因为受URL长度限制;Post传送的数据量较大,一般被默认为不受限制。
  3. Get限制Form表单的数据集的值必须为ASCII字符;而Post支持整个ISO10646字符集。
  4. Get执行效率却比Post方法好。Get是form提交的默认方法。 get是从服务器上获取数据,post是向服务器传送数据。

21、arrylist和linklist的区别?

  1. 1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
  2. 对于随机访问get和set,ArrayList优于LinkedList,因为ArrayList可以随机定位,而LinkedList要移动指针一步一步的移动到节点处。(参考数组与链表来思考)
  3. 对于新增和删除操作add和remove,LinedList比较占优势,只需要对指针进行修改即可,而ArrayList要移动数据来填补被删除的对象的空间。

22、string和stringBuffer,stringBuilder的区别?

  1. String类的内容一旦声明后是不可改变的,改变的只是其内存的指向,而StringBuffer类的对象内容是可以改变的。
  2. 对于StringBuffer,不能像String那样直接通过赋值的方式完成对象实例化,必须通过构造方法的方式完成。
  3. StringBuffer的在进行字符串处理时,不生成新的对象,在内存使用上要优于串类。所以在实际使用时,如果经常需要对一个字符串进行修改,例如插入,删除等操作,使用StringBuffer要更加适合一些。
  4. StringBuilder,StringBuffer 之间的最大不同在于 StringBuilder的方法不是线程安全的(不能同步访问)。
  5. StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类,然而在应用程序要求线程安全的情况下,则必须使用StringBuffer 类。

23、谈一下HashMap的特性?

1.HashMap的特性有哪些?
1.HashMap存储键值对实现快速存取,允许为null。key值不可重复,若key值重复则覆盖。
2.非同步,线程不安全。
3.底层是hash表,不保证有序(比如插入的顺序)

2.谈一下HashMap的底层原理是什么?
基于hashing的原理,jdk8后采用数组+链表+红黑树的数据结构。我们通过put和get存储和获取对象。当我们给put()方法传递键和值时,先对键做一个hashCode()的计算来得到它在bucket数组中的位置来存储Entry对象。当获取对象时,通过get获取到bucket的位置,再通过键对象的equals()方法找到正确的键值对,然后在返回值对象。
添加的时候进行hashCode计算出backet 然后进行entry对象的存储,获取的时候获取到bucket的位置,通过equals方法找到相对应的值然后返回对象。

3.谈一下hashMap中put是如何实现的?
hashMap中是如何添加的

  1. 首先,如果散列表为空时 ,直接调用resize()方法初始化列表
  2. 然后就是看发生碰撞没有 没有直接放入散列表中
  3. 最后发生了碰撞 则进行三个判断
    (1):key相同 或者内容相同 ,替换旧值
    (2):如果是红黑树结构,就调用树的插入方法
    (3):链表结构,循环遍历直到链表中某个节点为空,尾插法进行插入,插入之后判断链表个数是否到达变成红黑树的阙值8;也可以遍历到有节点与插入元素的哈希值和内容相同,进行覆盖。
    (4):如果桶满了大于阀值,则resize进行扩容

4.谈一下hashMap中什么时候需要进行扩容,扩容resize()又是如何实现的?

调用场景:

  • 初始化数组table
  • 当数组table的size达到阙值时即++size > load factor * capacity 时,也是在putVal函数中

实现过程:(细讲)

  • 通过判断旧数组的容量是否大于0来判断数组是否初始化过
    否:进行初始化
  • 判断是否调用无参构造器,
    是:使用默认的大小和阙值
    否:使用构造函数中初始化的容量,当然这个容量是经过tableSizefor计算后的2的次幂数
    是,进行扩容,扩容成两倍(小于最大值的情况下),之后在进行将元素重新进行与运算复制到新的散列表中
  • 概括的讲:扩容需要重新分配一个新数组,新数组是老数组的2倍长,然后遍历整个老结构,把所有的元素挨个重新hash分配到新结构中去。

5.谈一下hashMap中get是如何实现的?

  • 对key的hashCode进行hashing,与运算计算下标获取bucket位置,如果在桶的首位上就可以找到就直接返回,否则在树中找或者链表中遍历找,如果有hash冲突,则利用equals方法去遍历链表查找节点。

6.谈一下HashMap中hash函数是怎么实现的?还有哪些hash函数的实现方式?

  • 对key的hashCode做hash操作,与高16位做异或运算。
  • 还有平方取中法,除留余数法,伪随机数法。

24、HashMap和HashTable的区别?

相同点:都是存储key-value键值对的。
不同点:

  1. hashMap允许为空null,hashTable不允许
  2. map线程不安全,
  3. .HashMap允许Key-value为null,hashTable不允许;
  4. .hashMap没有考虑同步,是线程不安全的。hashTable是线程安全的,给api套上了一层
  5. synchronized修饰;
  6. HashMap继承于AbstractMap类,hashTable继承与Dictionary类。
  7. 容量的初始值和增加方式都不一样:HashMap默认的容量大小是16;增加容量时,每次将容量变为"原始容量x2"。Hashtable默认的容量大小是11;增加容量时,每次将容量变为"原始容量x2 + 1";
  8. 添加key-value时的hash值算法不同:HashMap添加元素时,是使用自定义的哈希算法。Hashtable没有自定义哈希算法,而直接采用的key的hashCode()。

25、传统hashMap的缺点(为什么引入红黑树?)

  • JDK 1.8 以前 HashMap 的实现是 数组+链表,即使哈希函数取得再好,也很难达到元素百分百均匀分布。
  • 当 HashMap中有大量的元素都存放到同一个桶中时,这个桶下有一条长长的链表,这个时候 HashMap 就相当于一个单链表,假如单链表有 n个元素,遍历的时间复杂度就是 O(n),完全失去了它的优势。
  • 针对这种情况,JDK 1.8 中引入了 红黑树(查找时间复杂度为
    O(logn))来优化这个问题。
相关标签: java