目录
- Spring 概述
- 依赖注入
- Spring beans
- Spring注解
- Spring数据访问
- Spring面向切面编程(AOP)
- Spring MVC
国外程序员整理的Java资源大全
Spring 概述
1. 什么是spring?
Spring 是个java企业级应用的开源开发框架。Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用。Spring 框架目标是简化Java企业级应用开发,并通过POJO为基础的编程模型促进良好的编程习惯。
2. 使用Spring框架的好处是什么?
- 轻量:Spring 是轻量的,基本的版本大约2MB。
- 控制反转:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。
- 面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。
- 容器:Spring 包含并管理应用中对象的生命周期和配置。
- MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。
- 事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。
- 异常处理:Spring 提供方便的API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛出的)转化为一致的unchecked 异常。
3. Spring由哪些模块组成?
以下是Spring 框架的基本模块:
- Core module
- Bean module
- Context module
- Expression Language module
- JDBC module
- ORM module
- OXM module
- Java Messaging Service(JMS) module
- Transaction module
- Web module
- Web-Servlet module
- Web-Struts module
- Web-Portlet module
4. 核心容器(应用上下文) 模块。
这是基本的Spring模块,提供spring 框架的基础功能,BeanFactory 是 任何以spring为基础的应用的核心。Spring 框架建立在此模块之上,它使Spring成为一个容器。
5. BeanFactory – BeanFactory 实现举例。
Bean 工厂是工厂模式的一个实现,提供了控制反转功能,用来把应用的配置和依赖从正真的应用代码中分离。
最常用的BeanFactory 实现是XmlBeanFactory 类。
6. XMLBeanFactory
最常用的就是org.springframework.beans.factory.xml.XmlBeanFactory ,它根据XML文件中的定义加载beans。该容器从XML 文件读取配置元数据并用它去创建一个完全配置的系统或应用。
7. 解释AOP模块
AOP模块用于发给我们的Spring应用做面向切面的开发, 很多支持由AOP联盟提供,这样就确保了Spring和其他AOP框架的共通性。这个模块将元数据编程引入Spring。
8. 解释JDBC抽象和DAO模块。
通过使用JDBC抽象和DAO模块,保证数据库代码的简洁,并能避免数据库资源错误关闭导致的问题,它在各种不同的数据库的错误信息之上,提供了一个统一的异常访问层。它还利用Spring的AOP 模块给Spring应用中的对象提供事务管理服务。
9. 解释对象/关系映射集成模块。
Spring 通过提供ORM模块,支持我们在直接JDBC之上使用一个对象/关系映射映射(ORM)工具,Spring 支持集成主流的ORM框架,如Hiberate,JDO和 iBATIS SQL Maps。Spring的事务管理同样支持以上所有ORM框架及JDBC。
10. 解释WEB 模块。
Spring的WEB模块是构建在application context 模块基础之上,提供一个适合web应用的上下文。这个模块也包括支持多种面向web的任务,如透明地处理多个文件上传请求和程序级请求参数的绑定到你的业务对象。它也有对Jakarta Struts的支持。
12. Spring配置文件
Spring配置文件是个XML 文件,这个文件包含了类信息,描述了如何配置它们,以及如何相互调用。
13. 什么是Spring IOC 容器?
Spring IOC 负责创建对象,管理对象(通过依赖注入(DI),装配对象,配置对象,并且管理这些对象的整个生命周期。
14. IOC的优点是什么?
IOC 或 依赖注入把应用的代码量降到最低。它使应用容易测试,单元测试不再需要单例和JNDI查找机制。最小的代价和最小的侵入性使松散耦合得以实现。IOC容器支持加载服务时的饿汉式初始化和懒加载。
15. ApplicationContext通常的实现是什么?
- FileSystemXmlApplicationContext :此容器从一个XML文件中加载beans的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。
- ClassPathXmlApplicationContext:此容器也从一个XML文件中加载beans的定义,这里,你需要正确设置classpath因为这个容器将在classpath里找bean配置。
- WebXmlApplicationContext:此容器加载一个XML文件,此文件定义了一个WEB应用的所有bean。
16. Bean 工厂和 Application contexts 有什么区别?
Application contexts提供一种方法处理文本消息,一个通常的做法是加载文件资源(比如镜像),它们可以向注册为监听器的bean发布事件。另外,在容器或容器内的对象上执行的那些不得不由bean工厂以程序化方式处理的操作,可以在Application contexts中以声明的方式处理。Application contexts实现了MessageSource接口,该接口的实现以可插拔的方式提供获取本地化消息的方法。
17. 一个Spring的应用看起来象什么?
- 一个定义了一些功能的接口。
- 这实现包括属性,它的Setter , getter 方法和函数等。
- Spring AOP。
- Spring 的XML 配置文件。
- 使用以上功能的客户端程序。
依赖注入
18. 什么是Spring的依赖注入?
依赖注入,是IOC的一个方面,是个通常的概念,它有多种解释。这概念是说你不用创建对象,而只需要描述它如何被创建。你不在代码里直接组装你的组件和服务,但是要在配置文件里描述哪些组件需要哪些服务,之后一个容器(IOC容器)负责把他们组装起来。
19. 有哪些不同类型的IOC(依赖注入)方式?
- 构造器依赖注入:构造器依赖注入通过容器触发一个类的构造器来实现的,该类有一系列参数,每个参数代表一个对其他类的依赖。
- Setter方法注入:Setter方法注入是容器通过调用无参构造器或无参static工厂 方法实例化bean之后,调用该bean的setter方法,即实现了基于setter的依赖注入。
20. 哪种依赖注入方式你建议使用,构造器注入,还是 Setter方法注入?
你两种依赖方式都可以使用,构造器注入和Setter方法注入。最好的解决方案是用构造器参数实现强制依赖,setter方法实现可选依赖。
Spring Beans
21.什么是Spring beans?
Spring beans 是那些形成Spring应用的主干的java对象。它们被Spring IOC容器初始化,装配,和管理。这些beans通过容器中配置的元数据创建。比如,以XML文件中<bean/> 的形式定义。
Spring 框架定义的beans都是单件beans。在bean tag中有个属性”singleton”,如果它被赋为TRUE,bean 就是单件,否则就是一个 prototype bean。默认是TRUE,所以所有在Spring框架中的beans 缺省都是单件。
22. 一个 Spring Bean 定义 包含什么?
一个Spring Bean 的定义包含容器必知的所有配置元数据,包括如何创建一个bean,它的生命周期详情及它的依赖。
23. 如何给Spring 容器提供配置元数据?
这里有三种重要的方法给Spring 容器提供配置元数据。
XML配置文件。
基于注解的配置。
基于java的配置。
24. 你怎样定义类的作用域?
当定义一个<bean> 在Spring里,我们还能给这个bean声明一个作用域。它可以通过bean 定义中的scope属性来定义。如,当Spring要在需要的时候每次生产一个新的bean实例,bean的scope属性被指定为prototype。另一方面,一个bean每次使用的时候必须返回同一个实例,这个bean的scope 属性 必须设为 singleton。
25. 解释Spring支持的几种bean的作用域。
Spring框架支持以下五种bean的作用域:
- singleton : bean在每个Spring ioc 容器中只有一个实例。
- prototype:一个bean的定义可以有多个实例。
- request:每次http请求都会创建一个bean,该作用域仅在基于web的Spring ApplicationContext情形下有效。
- session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
- global-session:在一个全局的HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
缺省的Spring bean 的作用域是Singleton.
26. Spring框架中的单例bean是线程安全的吗?
不,Spring框架中的单例bean不是线程安全的。
27. 解释Spring框架中bean的生命周期。
- Spring容器 从XML 文件中读取bean的定义,并实例化bean。
- Spring根据bean的定义填充所有的属性。
- 如果bean实现了BeanNameAware 接口,Spring 传递bean 的ID 到 setBeanName方法。
- 如果Bean 实现了 BeanFactoryAware 接口, Spring传递beanfactory 给setBeanFactory 方法。
- 如果有任何与bean相关联的BeanPostProcessors,Spring会在postProcesserBeforeInitialization()方法内调用它们。
- 如果bean实现IntializingBean了,调用它的afterPropertySet方法,如果bean声明了初始化方法,调用此初始化方法。
- 如果有BeanPostProcessors 和bean 关联,这些bean的postProcessAfterInitialization() 方法将被调用。
- 如果bean实现了 DisposableBean,它将调用destroy()方法。
28. 哪些是重要的bean生命周期方法? 你能重载它们吗?
有两个重要的bean 生命周期方法,第一个是setup , 它是在容器加载bean的时候被调用。第二个方法是 teardown 它是在容器卸载类的时候被调用。
The bean 标签有两个重要的属性(init-method和destroy-method)。用它们你可以自己定制初始化和注销方法。它们也有相应的注解(@PostConstruct和@PreDestroy)。
29. 什么是Spring的内部bean?
当一个bean仅被用作另一个bean的属性时,它能被声明为一个内部bean,为了定义inner bean,在Spring 的 基于XML的 配置元数据中,可以在 <property/>或 <constructor-arg/> 元素内使用<bean/> 元素,内部bean通常是匿名的,它们的Scope一般是prototype。
30. 在 Spring中如何注入一个java集合?
Spring提供以下几种集合的配置元素:
- <list>类型用于注入一列值,允许有相同的值。
- <set> 类型用于注入一组值,不允许有相同的值。
- <map> 类型用于注入一组键值对,键和值都可以为任意类型。
- <props>类型用于注入一组键值对,键和值都只能为String类型。
31. 什么是bean装配?
装配,或bean 装配是指在Spring 容器中把bean组装到一起,前提是容器需要知道bean的依赖关系,如何通过依赖注入来把它们装配到一起。
32. 什么是bean的自动装配?
Spring 容器能够自动装配相互合作的bean,这意味着容器不需要<constructor-arg>和<property>配置,能通过Bean工厂自动处理bean之间的协作。
33. 解释不同方式的自动装配 。
有五种自动装配的方式,可以用来指导Spring容器用自动装配方式来进行依赖注入。
- no:默认的方式是不进行自动装配,通过显式设置ref 属性来进行装配。
- byName:通过参数名 自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byname,之后容器试图匹配、装配和该bean的属性具有相同名字的bean。
- byType::通过参数类型自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byType,之后容器试图匹配、装配和该bean的属性具有相同类型的bean。如果有多个bean符合条件,则抛出错误。
- constructor:这个方式类似于byType, 但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常。
- autodetect:首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式。
34.自动装配有哪些局限性 ?
自动装配的局限性是:
- 重写: 你仍需用 <constructor-arg>和 <property> 配置来定义依赖,意味着总要重写自动装配。
- 基本数据类型:你不能自动装配简单的属性,如基本数据类型,String字符串,和类。
- 模糊特性:自动装配不如显式装配精确,如果有可能,建议使用显式装配。
35. 你可以在Spring中注入一个null 和一个空字符串吗?
可以。
Spring注解
36. 什么是基于Java的Spring注解配置? 给一些注解的例子.
基于Java的配置,允许你在少量的Java注解的帮助下,进行你的大部分Spring配置而非通过XML文件。
以@Configuration 注解为例,它用来标记类可以当做一个bean的定义,被Spring IOC容器使用。另一个例子是@Bean注解,它表示此方法将要返回一个对象,作为一个bean注册进Spring应用上下文。
37. 什么是基于注解的容器配置?
相对于XML文件,注解型的配置依赖于通过字节码元数据装配组件,而非尖括号的声明。
开发者通过在相应的类,方法或属性上使用注解的方式,直接组件类中进行配置,而不是使用xml表述bean的装配关系。
38. 怎样开启注解装配?
注解装配在默认情况下是不开启的,为了使用注解装配,我们必须在Spring配置文件中配置 <context:annotation-config/>元素。
39. @Required 注解
这个注解表明bean的属性必须在配置的时候设置,通过一个bean定义的显式的属性值或通过自动装配,若@Required注解的bean属性未被设置,容器将抛出BeanInitializationException。
40. @Autowired 注解
@Autowired 注解提供了更细粒度的控制,包括在何处以及如何完成自动装配。它的用法和@Required一样,修饰setter方法、构造器、属性或者具有任意名称和/或多个参数的PN方法。
41. @Qualifier 注解
当有多个相同类型的bean却只有一个需要自动装配时,将@Qualifier 注解和@Autowire 注解结合使用以消除这种混淆,指定需要装配的确切的bean。
Spring数据访问
42.在Spring框架中如何更有效地使用JDBC?
使用SpringJDBC 框架,资源管理和错误处理的代价都会被减轻。所以开发者只需写statements 和 queries从数据存取数据,JDBC也可以在Spring框架提供的模板类的帮助下更有效地被使用,这个模板叫JdbcTemplate (例子见这里here)
43. JdbcTemplate
JdbcTemplate 类提供了很多便利的方法解决诸如把数据库数据转变成基本数据类型或对象,执行写好的或可调用的数据库操作语句,提供自定义的数据错误处理。
44. Spring对DAO的支持
Spring对数据访问对象(DAO)的支持旨在简化它和数据访问技术如JDBC,Hibernate or JDO 结合使用。这使我们可以方便切换持久层。编码时也不用担心会捕获每种技术特有的异常。
45. 使用Spring通过什么方式访问Hibernate?
在Spring中有两种方式访问Hibernate:
- 控制反转 Hibernate Template和 Callback。
- 继承 HibernateDAOSupport提供一个AOP 拦截器。
46. Spring支持的ORM
Spring支持以下ORM:
- Hibernate
- iBatis
- JPA (Java Persistence API)
- TopLink
- JDO (Java Data Objects)
- OJB
47.如何通过HibernateDaoSupport将Spring和Hibernate结合起来?
用Spring的 SessionFactory 调用 LocalSessionFactory。集成过程分三步:
- 配置the Hibernate SessionFactory。
- 继承HibernateDaoSupport实现一个DAO。
- 在AOP支持的事务中装配。
48. Spring支持的事务管理类型
Spring支持两种类型的事务管理:
- 编程式事务管理:这意味你通过编程的方式管理事务,给你带来极大的灵活性,但是难维护。
- 声明式事务管理:这意味着你可以将业务代码和事务管理分离,你只需用注解和XML配置来管理事务。
49. Spring框架的事务管理有哪些优点?
- 它为不同的事务API 如 JTA,JDBC,Hibernate,JPA 和JDO,提供一个不变的编程模式。
- 它为编程式事务管理提供了一套简单的API而不是一些复杂的事务API如
- 它支持声明式事务管理。
- 它和Spring各种数据访问抽象层很好得集成。
50. 你更倾向用那种事务管理类型?
大多数Spring框架的用户选择声明式事务管理,因为它对应用代码的影响最小,因此更符合一个无侵入的轻量级容器的思想。声明式事务管理要优于编程式事务管理,虽然比编程式事务管理(这种方式允许你通过代码控制事务)少了一点灵活性。
Spring面向切面编程(AOP)
51. 解释AOP
面向切面的编程,或AOP, 是一种编程技术,允许程序模块化横向切割关注点,或横切典型的责任划分,如日志和事务管理。
52. Aspect 切面
AOP核心就是切面,它将多个类的通用行为封装成可重用的模块,该模块含有一组API提供横切功能。比如,一个日志模块可以被称作日志的AOP切面。根据需求的不同,一个应用程序可以有若干切面。在Spring AOP中,切面通过带有@Aspect注解的类实现。
52. 在Spring AOP 中,关注点和横切关注的区别是什么?
关注点是应用中一个模块的行为,一个关注点可能会被定义成一个我们想实现的一个功能。
横切关注点是一个关注点,此关注点是整个应用都会使用的功能,并影响整个应用,比如日志,安全和数据传输,几乎应用的每个模块都需要的功能。因此这些都属于横切关注点。
54. 连接点
连接点代表一个应用程序的某个位置,在这个位置我们可以插入一个AOP切面,它实际上是个应用程序执行Spring AOP的位置。
55. 通知
通知是个在方法执行前或执行后要做的动作,实际上是程序执行时要通过SpringAOP框架触发的代码段。
Spring切面可以应用五种类型的通知:
- before:前置通知,在一个方法执行前被调用。
- after: 在方法执行之后调用的通知,无论方法执行是否成功。
- after-returning: 仅当方法成功完成后执行的通知。
- after-throwing: 在方法抛出异常退出时执行的通知。
- around: 在方法执行之前和之后调用的通知。
56. 切点
切入点是一个或一组连接点,通知将在这些位置执行。可以通过表达式或匹配的方式指明切入点。
57. 什么是引入?
引入允许我们在已存在的类中增加新的方法和属性。
58. 什么是目标对象?
被一个或者多个切面所通知的对象。它通常是一个代理对象。也指被通知(advised)对象。
59. 什么是代理?
代理是通知目标对象后创建的对象。从客户端的角度看,代理对象和目标对象是一样的。
60. 有几种不同类型的自动代理?
BeanNameAutoProxyCreator
DefaultAdvisorAutoProxyCreator
Metadata autoproxying
61. 什么是织入。什么是织入应用的不同点?
织入是将切面和到其他应用类型或对象连接或创建一个被通知对象的过程。
织入可以在编译时,加载时,或运行时完成。
62. 解释基于XML Schema方式的切面实现。
在这种情况下,切面由常规类以及基于XML的配置实现。
63. 解释基于注解的切面实现
在这种情况下(基于@AspectJ的实现),涉及到的切面声明的风格与带有java5标注的普通java类一致。
Spring 的MVC
64. 什么是Spring的MVC框架?
Spring 配备构建Web 应用的全功能MVC框架。Spring可以很便捷地和其他MVC框架集成,如Struts,Spring 的MVC框架用控制反转把业务对象和控制逻辑清晰地隔离。它也允许以声明的方式把请求参数和业务对象绑定。
65. DispatcherServlet
Spring的MVC框架是围绕DispatcherServlet来设计的,它用来处理所有的HTTP请求和响应。
66. WebApplicationContext
WebApplicationContext 继承了ApplicationContext 并增加了一些WEB应用必备的特有功能,它不同于一般的ApplicationContext ,因为它能处理主题,并找到被关联的servlet。
67. 什么是Spring MVC框架的控制器?
控制器提供一个访问应用程序的行为,此行为通常通过服务接口实现。控制器解析用户输入并将其转换为一个由视图呈现给用户的模型。Spring用一个非常抽象的方式实现了一个控制层,允许用户创建多种用途的控制器。
68. @Controller 注解
该注解表明该类扮演控制器的角色,Spring不需要你继承任何其他控制器基类或引用Servlet API。
69. @RequestMapping 注解
该注解是用来映射一个URL到一个类或一个特定的方处理法上。
2.Spring知识点总结
chapter01 Spring简介
一、Spring是什么?
在了解Spring之前,我们来了解在Java EE框架下企业级开发采用EJB框架的一些不足:
(1) EJB太笨重,而且Entity EJB不能脱离容器
(2) 企业级服务使用困难
(3) 开发的复杂度太高
(4) 侵入式方案,EJB要使用特定的接口
因此,Spring应运而生。
Spring是一个开源的用于简化采用Java语言开发企业级程序的一个分层的框架。
关于程序的分层结构:
1、Presentation layer(表示层)
(1) 表示逻辑(生成界面代码)
(2) 接收请求
(3) 处理业务层抛出的异常
(4) 负责规则验证(数据格式,数据非空等)
(5) 流程控制
2、Service layer(服务层/业务层)
(1) 封装业务逻辑处理,并且对外暴露接口
(2) 负责事务,安全等服务
3、Persistence layer(持久层)
(1) 封装数据访问的逻辑,暴露接口
(2) 提供方便的数据访问的方案(查询语言,API,映射机制等)
Domain layer(域层)
(1) 业务对象以及业务关系的表示
(2) 处理简单的业务逻辑
(3) 域层的对象可以穿越表示层,业务层,持久层
二、Spring的作用
为什么要使用Spring?
(1) 简化企业级开发
① 封装了大部分的企业级服务,提供了更好的访问这些服务的方式
② 提供了IOC,AOP功能的容器,方便编程
(2) 遵循Spring框架的应用程序,一定是设计良好的,针对接口编程,这样就简化了企业级程序的设计。
(3) Spring的组成
① Spring Core:核心容器,BeanFactory提供了组件生命周期的管理,组件的创建,装配,销毁等功能
SpringContext:ApplicationContext,扩展核心容器,提供事件处理、国际化等功能。它提供了一些企业级服务的功能,提供了JNDI,EJB,RMI的支持。
② Spring AOP:提供切面支持
③ Spring DAO:提供事务支持,JDBC,DAO支持
④ Spring ORM:对流行的O/R Mapping封装或支持
⑤ Spring Web:提供Web应用上下文,对Web开发提供功能上的支持,如请求,表单,异常等。
⑥ Spring Web MVC:全功能MVC框架,作用等同于Struts。
chapter02 Spring的IoC
一、IoC的概念
IoC,Inversion of Control,控制反转。
对象的协作关系由对象自己负责。
依赖注入:对象的协作关系有容器来建立。
二、IoC的类型
(1) 基于特定接口(侵入式方案)
(2) 基于set方法
(3) 基于构造器
三、Spring容器
Spring容器负责生成、组装、销毁组件,并负责事件处理、国际化等功能。
(1) BeanFactory<interface>
① 核心容器,负责组件生成和装配
② 实现主要包括Xml BeanFactory
(2) ApplicationContext
(3) WebApplicationContext
(4) ……
四、IoC的使用
Resource:interface,用来包装资源
xmlBeanFactory:BeanFactory的一个实现,使用Resource对象来查找配置文件
BeanFactory.gerBean(“BeanId”):取得以参数命名,或者Id等于参数值的一个Bean实例。
BeanFactory(容器)在默认情况下,会采用单例方式返回对象。容器只到调用getBean方法时,才会实例化某个对象。
(1) Spring可以采用XML或者.properties文件作配置
(2) 配置文件(XML)
根元素<beans>可以有多个<bean>子元素,每个<bean>代表一个需要装配的对象。
1、setter注入
(1) 注入简单属性(String和8中基本类型)
<beans>
<bean id=”BeanId” class=”classpath” autowire=” ” dependency-check=” ”>
<property name=”parameterName”>
<value>parameterValue</value>
</property>
</bean>
</beans>
对于基本类型,Spring容器会自动作类型转换,以便赋值。
(2) 注入对象
<bean>
<ref local=”BeanId”>
</bean>
A、让Spring容器在当前配置文件中找到相应的Bean,并调用set方法,注入该Bean。
B、将一个Bean的定义嵌套在另一个Bean中(可读性差),被嵌套的Bean不能采用getBean()返回
C、采用<ref bean=” ”>搜索多个配置文件来注入
(3) 注入集合类型
① Set
Set中存放字符串,对象,集合,不允许重复
② List
List中可以放入字符串,对象,List
③ Map
Map 有<entry>子元素来存取key,value,key只能为String
④ Properties
Properties有<props>子元素
2、consctructor注入
<bean>
<constructor-arg>
<value></value>
</constructor-arg>
<constructor-arg>
<ref bean= “ ” />
</constructor-arg>
</bean>
如果Bean属性不多,并且属性值必须要注入才能使用,则应该采用constructor注入,其他情况就要set方法注入。
装配关系检查(Dependency checking)
simple:检查简单类型
ojects:检查对象类型
all:检查所有
<bean dependency-check=“all”></bean>
自动装配(Autowring Properties)
装配方式:byName,byType,autodetect,constructor
autowire=“byName”:按照名称匹配
按照Bean的Id与属性的名称进行匹配
自动装配与手动装配可以结合使用,手动装配会覆盖自动装配。
autowire=“byType”:按照类型匹配
要注入的属性类型与配置文件中的Bean类型匹配的个数超过一个,会出错。
autowire=“antodetect”:
先按照construct,后按照byType。
autowire=“constructor”:
先去匹配构造器中参数类型,后与配置文件中的Bean类型匹配。
3、比较两种注入方式
关于自动匹配:
优点:快速开发
缺点:依赖关系不清楚,易出错,不易维护。
自动匹配的应用场合:
(1) 构建系统原型
(2) 与依赖关系检查(Dependency-check)结合使用
(3) 自动装配与手动装配结合
4、特殊的IoC
① 后处理Bean
接口:org.springframework.beans.factory.config.BeanPostProcessor
Spring已经实现该接口的BeanPostProcessor(不用再注册)
ApplicationContextAwareProcessor:
把应用上下文传递给所用实现了 ApplicationContextAware接口的Bean
ApplicationContextAware接口使用举例,可参照事件监听机制
DefaultAdvisorAutoProxyCreator自动对Bean应用切面
② Bean工厂后处理(只能在应用上下文中使用)
接口:org.springframework.beans.factory.config.BeanFactoryPostProcessor
Spring内部接口实现:
org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
属性编辑
org.springframework.beans.factory.config.CustomEditorConfigurer
CustomerInfo(“fname-lname-address”)
实例工厂配置
代码:
——————————————————————————–
<beans>
<bean id=”car” class=”ioc3.Car” factory-bean=”carFactory” factory-method=”getCar” dependency-check=”all”>
<property name=”name”>
<value>奥迪A8</value>
</property>
<property name=”price”>
<value>800000.0</value>
</property>
</bean>
<bean id=”carFactory” class=”ioc3.CarFactory”/>
</beans>
——————————————————————————–
静态工厂配置
——————————————————————————–
<beans>
<bean id=”car” class=”ioc3.CarFactory” factory-method=”getCar”>
<property name=”name”>
<value>奥迪A8</value>
</property>
<property name=”price”>
<value>800000.0</value>
</property>
</bean>
</beans>
——————————————————————————–
5、事件处理
事件监听
1)自定义事件,通过继承org.springframework.context.ApplicationEvent
2)自定义监听器,实现 org.springframework.context.ApplicationListener,并注册
3)发布事件,为得到应用上下文,
必须实现org.springframework.context.ApplicationContextAware接口
chapter03 Spring的AOP
一、AOP(Aspect-oriented programming,面向切面编程):
什么是AOP?
定义:将程序中的交叉业务逻辑提取出来,称之为切面。将这些切面动态织入到目标对象,然后生成一个代理对象的过程。
二、AOP核心概念
1、Aspect(切面)
切面,是对交叉业务逻辑的统称。
2、Joinpoint(连接点)
连接点,指切面可以织入到目标对象的位置(方法,属性等)。
3、Advice(通知)
通知,指切面的具体实现。
4、Pointcut(切入点)
切入点,指通知应用到哪些类的哪些方法或属性之上的规则。
5、Introduction(引入)
引入,指动态地给一个对象增加方法或属性的一种特殊的通知。
6、Weaving(织入)
织入,指将通知插入到目标对象。
7、Target(目标对象)
目标对象,指需要织入切面的对象。
8、Proxy(代理对象)
代理对象,指切面织入目标对象之后形成的对象。
三、Spring AOP原理
采用动态代理模式。
Spring AOP采用动态代理的过程:
(1) 将切面使用动态代理的方式动态织入到目标对象(被代理类),形成一个代理对象;
(2) 目标对象如果没有实现代理接口,那么Spring会采用CGLib来生成代理对象,该代理对象是目标对象的子类;
(3) 目标对象如果是final类,并且也没实现代理接口,就不能运用AOP。
四、Spring的通知
1、Spring的通知类型
(1) MethodBeforeAdvice
类全名:org.springframework.aop.MethodBeforeAdvice
在方法调用之前,做处理。
不能够改变返回值
不能够改变目标方法的流程,也不能中断流程的处理过程(除非抛出异常)
(2) AfterReturningAdvice
类全名:org.springframework.aop.AfterReturningAdvice
在方法调用之后,做处理。
不能够改变返回值
不能够改变目标方法的流程,也不能中断流程的处理过程(除非抛出异常)
(3) MethodInterceptor
类全名:org.aopalliance.intercept.MethodInterceptor
在方法调用之前以及之后,做处理。
可以改变返回值,也可以改变流程。
(4) ThrowsAdvice
类全名:org.springframework.aop.ThrowsAdvice
在方法抛出异常后,做处理。
当该通知处理完异常后,会简单地将异常再次抛出给目标调用方法。
2、配置过程:
(1)配置目标对象
(2)配置通知
(3)利用ProxyFactoryBean将通知织入到目标对象,形成一个动态代理对象
(4)客户端使用动态代理来访问目标对象的方法。
在默认情况下,通知会应用到所有的方法之上。
Pointcut:
根据方法和类决定在什么地方织入通知
Advisor:
将Pointcut与Advice结合到一起。
自定义切入点:
步骤:
1)实现org.springframework.aop.ClassFilter
2)实现org.springframework.aop.MethodMatcher
3)实现org.springframework.aop.Pointcut
4)实现org.springframework.aop.PointcutAdvisor
注意:
在此可定义
private Advice advice;
private Pointcut pointcut;
在配置文件中,将自定义的切入点与通知绑订到一起
5)利用ProxyFactoryBean将advisor织入到目标对象
ProxyFactoryBean的作用:
依照配置信息,将切面应用到目标对象,生成动态代理对象。
(1) Spring只支持方法连接点,不支持属性连接点。
(原因是Spring AOP采用的是动态代理模式,而动态代理本身就是在方法调用前加入代码。)
(2) Spring只在运行时,将切面织入到目标对象。
(有些AOP实现,可以在编译是织入切面到目标对象。)
Injecting Advice(con’t d)
<bean id=”registerService’ class=”org.springframework.aop.framework.ProxyFactoryBean”>
<property name=”proxyInterfaces”> ←目标对象实现的接口
(如果没有定义接口,则所有方法使用CGLib
<value>aop.RegisterService</value>
</proxy>
<property name=”target”> ←目标对象
<ref local=”registerServiceTarget”/>
</property>
<property name=”interceptorNames”> ←需要织入到目标对象的切面
<list>
<value>logAdvice</value>
<value>throwsAdvice</value>
</list>
</property>
</bean>
五、切入点(Pointcut)
1、Pointcut<interface>
切入点是指通知/切面可以应用到哪些类,哪些方法之上。
Pointcut API
Pointcut:org.springframework.aop.Pointcut
对某些类某些方法应用切面。
Classfilter:org.springframework.aop.ClassFilter
用来过滤类(哪些类可以应用切面)
MethodMather:org.springframework.aop.MethodMatcher
用来过滤方法(类中哪些方法应用切面)
Advisor:org.springframework.aop.PointcutAdvisor
将Pointcut与Advice结合到一起
配置文件样例:
<beans>
<bean id=”registerServiceTarget” class=”aop5.RegisterService”/>
<bean id=”logAdvice” class=”aop5.LogAdvice”/>
<bean id=”myPointcut” class=”aop5.MyPointcut”/>
<bean id=”myPointcutAdvisor” class=”aop5.MyPointcutAdvisor”>
<property name=”advice”>
<ref local=”logAdvice”/>
</property>
<property name=”pointcut”>
<ref local=”myPointcut”/>
</property>
</bean>
<bean id=”registerService” class=”org.springframework.aop.framework.ProxyFactoryBean”>
<property name=”target”>
<ref local=”registerServiceTarget”/>
</property>
<property name=”interceptorNames”>
<list>
<value>myPointcutAdvisor</value>
</list>
</property>
</bean>
</beans>
2、预定义切入点
① 静态切入点:
a、NameMatchMethodPointAdviosr
org.springframework.aop.support.NameMatchMethodPointcutAdvisor
根据方法名称的特点进行匹配
核心XML:mappedName→advice(ref)
配置文件样例:
<beans>
<bean id=”registerServiceTarget” class=”aop6.RegisterService” />
<bean id=”logAdvice” class=”aop6.LogAdvice” />
<bean id=”namedPointcutAdvisor” class=”org.springframework.aop.support.NameMatchMethodPointcutAdvisor”>
<property name=”mappedName”>
<value>methodOne</value>
</property>
<property name=”advice”>
<ref local=”logAdvice”/>
</property>
</bean>
<bean id=”registerService”
class=”org.springframework.aop.framework.ProxyFactoryBean”>
<property name=”target”>
<ref local=”registerServiceTarget” />
</property>
<property name=”interceptorNames”>
<list>
<value>namedPointcutAdvisor</value>
</list>
</property>
</bean>
</beans>
b、RegexpMethodPointcutAdvisor
根据正则表达式匹配方法名
org.springframework.aop.support.RegexpMethodPointcutAdvisor
核心XML:pattern→advice(ref)
配置文件样例:
<beans >
<bean id=”registerServiceTarget” class=”aop6.RegisterService” />
<bean id=”logAdvice” class=”aop6.LogAdvice” />
<bean id=”regexpAdvisor” class=”org.springframework.aop.support.RegexpMethodPointcutAdvisor”>
<property name=”pattern”>
<value>.*method.*</value>
</property>
<property name=”advice”>
<ref local=”logAdvice”/>
</property>
</bean>
<bean id=”registerService”
class=”org.springframework.aop.framework.ProxyFactoryBean”>
<property name=”target”>
<ref local=”registerServiceTarget” />
</property>
<property name=”interceptorNames”>
<list>
<value>regexpAdvisor</value>
</list>
</property>
</bean>
</beans>
② 动态切入点:
org.springframework.aop.support.ControlFlowPointcut
③ 切入点的交叉与合并:
Pointcuts.union
配置文件样例:
<bean id=”unionPointcut” class=”aop7.UnionPointcut”>
<property name=”pointcuts”>
<list>
<ref local=”myPointcut”/>
<ref local=”otherPointcut”/>
</list>
</property>
</bean>
<bean id=”myPointcutAdvisor” class=”aop7.MyPointcutAdvisor”>
<property name=”advice”>
<ref local=”logAdvice”/>
</property>
<property name=”pointcut”>
<ref local=”unionPointcut”/>
</property>
</bean>
④ Introduction
一种特殊类型的Advice,为类动态增加方法和属性。
编程步骤:
1)实现org.springframework.aop.IntroductionInterceptor或
继承org.springframework.aop.support.DelegatingIntroductionInterceptor
2)使用org.springframework.aop.support.DefaultIntroductionAdvisor
配置文件样例:
<bean id=”myIntroInterceptor” class=”aop8.MyIntroductionInterceptor”/>
<bean id=”myIntroInterceptorAdvisor” class=”org.springframework.aop.support.DefaultIntroductionAdvisor”>
<constructor-arg>
<ref local=”myIntroInterceptor”/>
</constructor-arg>
<constructor-arg>
<value>aop8.OtherBean</value>
</constructor-arg>
</bean>
六、自动代理
Spring在生成代理对象的时候,默认情况下,会使用被代理对象的接口来生成代理对象。
如果被代理对象没有实现接口,此时,Spring会使用CGLIB生成代理对象,此时该代理对象是被代理对象的子类。
a、BeanNameAutoProxyCreator
org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator
根据类的名称来为符合相应名称的类生成相应代理对象。
beanNames(list),interceptorNames
配置文件样例:
<bean id=”namedProxyCreator” class=”org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator”>
<property name=”beanNames”>
<list>
<value>someService</value>
<value>otherService</value>
</list>
</property>
<property name=”interceptorNames”>
<list>
<value>logAdvice</value>
</list>
</property>
</bean>
b、DefaultAdvisorAutoProxyCreator
org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator
自动将Advisor与匹配的Bean进行绑定
只能与Advisor配合使用
配置文件样例:
<bean id=”autoProxyCreator” class=”org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator”/>
chapter04 Spring对持久层的支持
Spring对持久层的支持:① JDBC,② O/R Mapping(Hibernate,TopLink等)
一、Spring对持久层支持采用的策略:
1、Spring对持久层“不发明重复的轮子”,即没有重新实现新的持久层方案,对现有持久层方案做封装,更利于使用。
2、采用DAO模式
3、提供了大量的模板类来简化编程(HibernateDaoSupport,JdbcTemplate等)
4、重新设计了一套完善的异常体系结构
① 类型丰富,细化异常类型
② 全都是运行时异常(RuntimeException)
二、Spring对JDBC的支持
1、配置数据源
方式一:采用Spring内置的数据源,Spring内置实现 DriverManagerDataSource
<bean id=”dataSource” class=”org.springframework.jdbc.datasource.DriverManagerDataSource”>
<property name=”driverClassName”>
<value>com.mysql.jdbc.Driver</value>
</property>
<property name=”url”>
<value>jdbc:mysql://localhost:3306/hibdb</value>
</property>
<property name=”username”>
<value>root</value>
</property>
<property name=”password”>
<value>windows</value>
</property>
</bean>
方式二:采用开源数据库产品如DBCP
DBCP提供的BasicDataSource
<bean id=”dataSource” class=”org.apache.commons.dbcp.BasicDataSource”>
<property name=”driverClassName”>
<value>com.mysql.jdbc.Driver</value>
</property>
<property name=”url”>
<value>jdbc:mysql://localhost:3306/hibdb</value>
</property>
<property name=”username”>
<value>root</value>
</property>
<property name=”password”>
<value>windows</value>
</property>
</bean>
方式三: 直接使用容器提供的数据源(如Tomcat,Weblogic,Sun Application Server)
JNDI数据源:(mysql5,tomcat5.5)
step1:
在server.xml中:
<Resource name=”jdbc/mydatasource” auth=”Container” description=”DB Connection”
type=”javax.sql.DataSource” username=”root” password=”windows”
driverClassName=”com.mysql.jdbc.Driver”
url=”jdbc:mysql://localhost:3306/tarena” maxActive=”5” />
step2:
在context.xml中(conf\context.xml):
<ResourceLink name=”jdbc/mydatasource” global=”jdbc/mydatasource” type=”javax.sql.DataSourcer”/>
step3:
在beans-config.xml:
<bean id=”dataSource” class=”org.springframework.jndi.JndiObjectFactoryBean”>
<property name=”jndiName”>
<value>java:comp/env/jdbc/mydatasource</value>
</property>
</bean>
2、配置JdbcTemplate模板类(封装了绝大多数数据库操作)
3、配置DAO
4、配置Service
编程步骤:
step1: 配置数据源
step2: 配置JdbcTemplate
<bean id=”jdbcTemplate”
class=”org.springframework.jdbc.core.JdbcTemplate”>
<property name=”dataSource”>
<ref bean=”dataSource” />
</property>
</bean>
step3:配置DAO
<bean id=”orderDao” class=”lab5.OrderDAOImpl”>
<property name=”jt”><ref bean=”jdbcTemplate”/></property>
</bean>
注意: 查询时,使用RowMapper
三、Spring对Hibernate的支持
Step1: 配置数据源
Step2: 配置sessionfactory
<bean id=”mySessionFactory”
class=”org.springframework.orm.hibernate3.LocalSessionFactoryBean”>
<property name=”dataSource”>
<ref bean=”dataSource” />
</property>
<property name=”mappingResources”>
<list>
<value>lab6/Order.hbm.xml</value>
</list>
</property>
<property name=”hibernateProperties”>
<props>
<prop key=”hibernate.dialect”>
org.hibernate.dialect.MySQLDialect
</prop>
<prop key=”hibernate.show_sql”>true</prop>
</props>
</property>
</bean>
Step3: 配置DAO
<bean id=”orderDao” class=”lab6.OrderDAOHibernateImpl”>
<property name=”sessionFactory”>
<ref bean=”mySessionFactory” />
</property>
</bean>
注意:以上配置是要求dao 继承HibernateDaoSupport
chapter05 Spring对事务的支持
一、AOP事务的含义:
事务当作一个切面,动态地织入到目标对象,形成一个代理对象。
二、Spring的事务机制
Spring支持声明式事务。
Spring使用事务服务代理和事务管理器(如HibernateTransactionManager)来支持事务服务。
Spring对事务的边界多了一种嵌套事务(PROPAGATION_NESTED)。
PROPAGATION_NESTED:
如果客户端启动了事务T1,那么Bean启动一个嵌套在T1中的子事务T2;
如果客户端没有启动事务,那么Bean会启动一个新的事务,类似于REQUIRED_NEW
三、Spring中事务的使用
1、Spring中使用Hibernate事务
Step1:配置数据源
Step2:配置sessionfactory (同上)
Step3:配置事务管理器
<bean id=”myTransactionManager”
class=”org.springframework.orm.hibernate3.HibernateTransactionManager”>
<property name=”sessionFactory”>
<ref bean=”mySessionFactory” />
</property>
</bean>
Step4:创建事务服务代理
<bean id=”saleService”
class=”org.springframework.transaction.interceptor.TransactionProxyFactoryBean”>
<property name=”proxyInterfaces”>
<value>lab7.SaleService</value>
</property>
<property name=”transactionManager”>
<ref bean=”myTransactionManager” />
</property>
<property name=”target”>
<ref bean=”saleServiceTarget” />
</property>
<property name=”transactionAttributes”>
<props>
<prop key=”*”>PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
事务属性描述格式:
传播行为,隔离级别,只读事务(read-only),回滚规则
在默认情况下,Spring的容器对于非受查异常(服务模块中抛出的非受查异常),会回滚事务。对于受查异常,会提交事务。
如果即使发生了某种受查异常,也要回滚事务,可以用 “- 异常类型“来声明。同样,对于非受查异常,如果不要求回滚事务,可以用”+异常类型”来声明。
如何简化事务配置?
使用继承(抽象的Service类)、自动代理。
四、Spring事务与EJB事务
1、EJB事务:
EJB的CMT管理事务方式,只能设置事务边界(传播行为),对于隔离性是不能设置的,并且EJB不支持嵌套事务。
2、Spring事务:
对于Spring来说, Spring的声明式事务可以设置事务边界(传播行为),设置隔离级别,设置只读事务,回滚规则(+:对于任何异常都提交,-:对于任何异常都回滚)
<property name=”transactionAttributes”>
<props>
<prop key=”*”>+异常类型1,-异常类型2</prop>
</property>
PS:Spring对嵌套事务的支持依赖与数据库底层对嵌套式事务的支持。
chapter06 SSH整合
一、SSH:
Struts(表示层)+Spring(业务层)+Hibernate(持久层)
Struts:
Struts是一个表示层框架,主要作用是界面展示,接收请求,分发请求。
在MVC框架中,Struts属于VC层次,负责界面表现,负责MVC关系的分发。(View:沿用JSP,HTTP,Form,Tag,Resourse ;Controller:ActionServlet,struts-config.xml,Action)
Hibernate:
Hibernate是一个持久层框架,它只负责与关系数据库的操作。
Spring:
Spring是一个业务层框架,是一个整合的框架,能够很好地黏合表示层与持久层。
① Web分层架构中业务层为什么都选择Spring?
Service层需要处理业务逻辑和交叉业务逻辑,处理事务,日志,安全等,而这些与Spring的IoC,AOP等不谋而合。
② Web分层架构中,对于各层技术的采用应该遵循一个怎样的标准?
1、选择发展成熟的技术:
A、经过了项目实践证实可行性良好
B、文档完善
C、技术一直处于可持续发展更新
2、Web应用中对于技术的选择有赖于开发人员的技术掌握情况
二、Spring与Struts整合
前提:
必须在Web应用启动时,创建Spring的ApplicationContext实例
方式:
1、采用ContextLoaderListener来创建ApplicationContext:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-config/applicationContext.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
2、采用ContextLoaderPlugIn来创建ApplicationContext
<plug-in className=”org.springframework.web.struts.ContextLoaderPlugIn”>
<set-property property=”contextConfigLocation” value=”/WEB-INF/config/sale.xml” />
</plug-in>
或者:
通过listener装载spring应用上下文
方式一:通过Spring的ActionSupport类
ActionSupport类:
知道ApplicationContext的获得方式。
步骤:
1、Action直接继承ActionSupport
2、使用ApplicationContext ctx = getWebApplicationContext();取得Spring上下文
3、取得相应Bean
注意:有可能需要替换commons-attributes-compiler.jar包。
优点:
简单
缺点:
耦合高
违反IOC
无法使用多方法的Action
方式二:通过Spring的DelegatingActionProxy类
步骤:
1、Action中,使用IOC获得服务
2、配置struts-config.xml
<action path=”/somepath” type=”org.springframework.web.struts.DelegatingActionProxy”/>
3、在Spring配置文件中
<bean name=”/somepath” class=”SomeAction”>
<property name=”service”><ref bean=”“/>
</bean>
注意,要用bean name命名。
/somepath:Action的path
优点:
不使用Spring api编写 Action
利用了IOC装配。
可以利用容器的scope=”prototype”来保证每一个请求有一个单独的Action来处理,
避免struts中Action的线程安全问题。
缺点:
struts配置文件中,所有path都映射到同一个代理类
方式三:通过Spring的DelegatingRequestProcessor类
步骤:
1、Action中,使用IOC获得服务
2、配置struts-config.xml
<controller processorClass=”org.springframework.web.struts.DelegatingRequestProcessor” />
3、在Spring配置文件中
<bean name=”/somepath” class=”SomeAction”>
<property name=”service”><ref bean=”“/>
</bean>
小结:
Spring与Struts整合方式只有两种:
(1)由Spring容器来管理Action(方式二,方式三)
(2)Action处于容器之外(方式一)
注意:
中文问题:
设置过滤器,设置页面编码,数据库编码
三、关于Spring与EJB
1、Spring与EJB3.0的对比
Spring与EJB3.0之间的关系是竞争关系。
① Spring是一个开源的框架,而EJB3.0是一个标准(标准意味着将得到广泛的支持以及良好的兼容性),并且,采用EJB3.0,项目的后期维护得到了保证。
② Spring是一个轻量级框架,EJB3.0是一个重量级框架(完整的容器,包含所有的服务)。
③ Spring的IoC,AOP集成了大量的开源框架,可扩展性良好。EJB3.0的可扩展性则完全依赖于新的容器。
④ Spring对事务支持不如EJB3.0成熟,Spring对集群的兼容也不够。
⑤ Spring与EJB3.0都是一个企业级开发框架,都支持声明式事务。
2、Spring的优势与劣势
Spring的优势:
① 简化了企业级开发(对企业级服务进行了进一步的封装)
② 采用Spring框架的程序意味着良好的分层结构设计,并保证是面向接口编程的
③ 用IoC,AOP容器,模块是可配置的,松耦合的,方便了后期维护
Spring的劣势:
① 配置复杂,不方便维护
② 容器大量使用反射等机制装配对象,影响性能,对于高并发的大型应用无能为力。
给程序员和开发者的 10 道 Java 泛型面试题
Java泛型面试题
1. Java中的泛型是什么 ? 使用泛型的好处是什么?
这是在各种Java泛型面试中,一开场你就会被问到的问题中的一个,主要集中在初级和中级面试中。那些拥有Java1.4或更早版本的开发背景的人都知道,在集合中存储对象并在使用前进行类型转换是多么的不方便。泛型防止了那种情况的发生。它提供了编译期的类型安全,确保你只能把正确类型的对象放入集合中,避免了在运行时出现ClassCastException。
2. Java的泛型是如何工作的 ? 什么是类型擦除 ?
这是一道更好的泛型面试题。泛型是通过类型擦除来实现的,编译器在编译时擦除了所有类型相关的信息,所以在运行时不存在任何类型相关的信息。例如List<String>在运行时仅用一个List来表示。这样做的目的,是确保能和Java 5之前的版本开发二进制类库进行兼容。你无法在运行时访问到类型参数,因为编译器已经把泛型类型转换成了原始类型。根据你对这个泛型问题的回答情况,你会得到一些后续提问,比如为什么泛型是由类型擦除来实现的或者给你展示一些会导致编译器出错的错误泛型代码。请阅读我的Java中泛型是如何工作的来了解更多信息。
3. 什么是泛型中的限定通配符和非限定通配符 ?
这是另一个非常流行的Java泛型面试题。限定通配符对类型进行了限制。有两种限定通配符,一种是<? extends T>它通过确保类型必须是T的子类来设定类型的上界,另一种是<? super T>它通过确保类型必须是T的父类来设定类型的下界。泛型类型必须用限定内的类型来进行初始化,否则会导致编译错误。另一方面<?>表示了非限定通配符,因为<?>可以用任意类型来替代。更多信息请参阅我的文章泛型中限定通配符和非限定通配符之间的区别。
4. List<? extends T>和List <? super T>之间有什么区别 ?
这和上一个面试题有联系,有时面试官会用这个问题来评估你对泛型的理解,而不是直接问你什么是限定通配符和非限定通配符。这两个List的声明都是限定通配符的例子,List<? extends T>可以接受任何继承自T的类型的List,而List<? super T>可以接受任何T的父类构成的List。例如List<? extends Number>可以接受List<Integer>或List<Float>。在本段出现的连接中可以找到更多信息。
5. 如何编写一个泛型方法,让它能接受泛型参数并返回泛型类型?
编写泛型方法并不困难,你需要用泛型类型来替代原始类型,比如使用T, E or K,V等被广泛认可的类型占位符。泛型方法的例子请参阅Java集合类框架。最简单的情况下,一个泛型方法可能会像这样:
1
2
3
|
public
V put(K key, V value) {
return
cache.put(key, value);
}
|
6. Java中如何使用泛型编写带有参数的类?
这是上一道面试题的延伸。面试官可能会要求你用泛型编写一个类型安全的类,而不是编写一个泛型方法。关键仍然是使用泛型类型来代替原始类型,而且要使用JDK中采用的标准占位符。
7. 编写一段泛型程序来实现LRU缓存?
对于喜欢Java编程的人来说这相当于是一次练习。给你个提示,LinkedHashMap可以用来实现固定大小的LRU缓存,当LRU缓存已经满了的时候,它会把最老的键值对移出缓存。LinkedHashMap提供了一个称为removeEldestEntry()的方法,该方法会被put()和putAll()调用来删除最老的键值对。当然,如果你已经编写了一个可运行的JUnit测试,你也可以随意编写你自己的实现代码。
8. 你可以把List<String>传递给一个接受List<Object>参数的方法吗?
对任何一个不太熟悉泛型的人来说,这个Java泛型题目看起来令人疑惑,因为乍看起来String是一种Object,所以List<String>应当可以用在需要List<Object>的地方,但是事实并非如此。真这样做的话会导致编译错误。如果你再深一步考虑,你会发现Java这样做是有意义的,因为List<Object>可以存储任何类型的对象包括String, Integer等等,而List<String>却只能用来存储Strings。
1
2
3
4
|
List<Object> objectList;
List<String> stringList;
objectList = stringList;
//compilation error incompatible types
|
9. Array中可以用泛型吗?
这可能是Java泛型面试题中最简单的一个了,当然前提是你要知道Array事实上并不支持泛型,这也是为什么Joshua Bloch在Effective Java一书中建议使用List来代替Array,因为List可以提供编译期的类型安全保证,而Array却不能。
10. 如何阻止Java中的类型未检查的警告?
如果你把泛型和原始类型混合起来使用,例如下列代码,Java 5的javac编译器会产生类型未检查的警告,例如
1
2
|
List<String> rawList =
new
ArrayList()
注意: Hello.java使用了未检查或称为不安全的操作;
|
这种警告可以使用@SuppressWarnings(“unchecked”)注解来屏蔽。
Java泛型面试题补充更新:
我手头又拿到了几个Java泛型面试题跟大家分享下,这几道题集中在泛型类型和原始类型的区别上,以及我们是否可以用Object来代替限定通配符的使用等等:
Java中List<Object>和原始类型List之间的区别?
原始类型和带参数类型<Object>之间的主要区别是,在编译时编译器不会对原始类型进行类型安全检查,却会对带参数的类型进行检查,通过使用Object作为类型,可以告知编译器该方法可以接受任何类型的对象,比如String或Integer。这道题的考察点在于对泛型中原始类型的正确理解。它们之间的第二点区别是,你可以把任何带参数的类型传递给原始类型List,但却不能把List<String>传递给接受List<Object>的方法,因为会产生变异错误。更多详细信息请参阅Java中的泛型是如何工作的。
Java中List<?>和List<Object>之间的区别是什么?
这道题跟上一道题看起来很像,实质上却完全不同。List<?> 是一个未知类型的List,而List<Object>其实是任意类型的List。你可以把List<String>, List<Integer>赋值给List<?>,却不能把List<String>赋值给List<Object>。
1
2
3
4
5
6
7
8
|
List<?> listOfAnyType;
List<Object> listOfObject =
new
ArrayList<Object>();
List<String> listOfString =
new
ArrayList<String>();
List<Integer> listOfInteger =
new
ArrayList<Integer>();
listOfAnyType = listOfString;
//legal
listOfAnyType = listOfInteger;
//legal
listOfObjectType = (List<Object>) listOfString;
//compiler error - in-convertible types
|
想了解更多关于通配符的信息请查看Java中的泛型通配符示例
List<String>和原始类型List之间的区别.
该题类似于“原始类型和带参数类型之间有什么区别”。带参数类型是类型安全的,而且其类型安全是由编译器保证的,但原始类型List却不是类型安全的。你不能把String之外的任何其它类型的Object存入String类型的List中,而你可以把任何类型的对象存入原始List中。使用泛型的带参数类型你不需要进行类型转换,但是对于原始类型,你则需要进行显式的类型转换。
1
2
3
4
5
6
7
8
9
10
|
List listOfRawTypes =
new
ArrayList();
listOfRawTypes.add(
"abc"
);
listOfRawTypes.add(
123
);
//编译器允许这样 - 运行时却会出现异常
String item = (String) listOfRawTypes.get(
0
);
//需要显式的类型转换
item = (String) listOfRawTypes.get(
1
);
//抛ClassCastException,因为Integer不能被转换为String
List<String> listOfString =
new
ArrayList();
listOfString.add(
"abcd"
);
listOfString.add(
1234
);
//编译错误,比在运行时抛异常要好
item = listOfString.get(
0
);
//不需要显式的类型转换 - 编译器自动转换
|