java枚举学习
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
DK1.5引入了新的类型——枚举。
在Java中它虽然算个“小”功能,却给我的开发带来了“大”方便。
用法一:常量
在JDK1.5之前,我们定义常量都是:publicstaticfianl....。
现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法。
Java代码
1.public enum Color {
2. RED, GREEN, BLANK, YELLOW
3.}
用法二:switch
JDK1.6之前的switch语句只支持int,char,enum类型,使用枚举,能让我们的代码可读性更强。
Java代码
1.enum Signal {
2. GREEN, YELLOW, RED
3.}
4.public class TrafficLight {
5. Signal color = Signal.RED;
6. public void change() {
7. switch (color) {
8. case RED:
9. color = Signal.GREEN;
10. break ;
11. case YELLOW:
12. color = Signal.RED;
13. break ;
14. case GREEN:
15. color = Signal.YELLOW;
16. break ;
17. }
18. }
19.}
用法三:向枚举中添加新方法
如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号。
而且Java要求必须先定义enum实例。
Java代码
1.public enum Color {
2. RED("红色" , 1 ), GREEN( "绿色" , 2 ), BLANK( "白色
" , 3 ), YELLO( "黄色" , 4 );
3. // 成员变量
4. private String name;
5. private int index;
6. // 构造方法
7. private Color(String name, int index) {
8. this .name = name;
9. this .index = index;
10. }
11. // 普通方法
12. public static String getName( int index) {
13. for (Color c : Color.values()) {
14. if (c.getIndex() == index) {
15. return ;
16. }
17. }
18. return null ;
19. }
20. // get set 方法
21. public String getName() {
22. return name;
23. }
24. public void setName(String name) {
25. this .name = name;
26. }
27. public int getIndex() {
28. return index;
29. }
30. public void setIndex( int index) {
31. this .index = index;
32. }
33.}
用法四:覆盖枚举的方法
下面给出一个toString()方法覆盖的例子。
Java代码
1.public enum Color {
2. RED("红色" , 1 ), GREEN( "绿色" , 2 ), BLANK( "白色
" , 3 ), YELLO( "黄色" , 4 );
3. // 成员变量
4. private String name;
5. private int index;
6. // 构造方法
7. private Color(String name, int index) {
8. this .name = name;
9. this .index = index;
10. }
11. //覆盖方法
12. @Override
13. public String toString() {
14. return this .index+ "_" + this .name;
15. }
16.}
用法五:实现接口
所有的枚举都继承自ng.Enum类。
由于Java不支持多继承,所以枚举对象不能再继承其他类。
Java代码
1.public interface Behaviour {
2. void print();
3. String getInfo();
4.}
5.public enum Color implements Behaviour{
6. RED("红色" , 1 ), GREEN( "绿色" , 2 ), BLANK( "白色
" , 3 ), YELLO( "黄色" , 4 );
7. // 成员变量
8. private String name;
9. private int index;
10. // 构造方法
11. private Color(String name, int index) {
12. this .name = name;
13. this .index = index;
14. }
15.//接口方法
16. @Override
17. public String getInfo() {
18. return this .name;
19. }
20. //接口方法
21. @Override
22. public void print() {
23. System.out.println(this .index+ ":" + this .name);
24. }
25.}
用法六:使用接口组织枚举
Java代码
1.public interface Food {
2. enum Coffee implements Food{
3. BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO
4. }
5. enum Dessert implements Food{
6. FRUIT, CAKE, GELATO
7. }
8.}
用法七:关于枚举集合的使用
java.util.EnumSet和java.util.EnumMap是两个枚举集合。
EnumSet保证集合中的元素不重复;EnumMap中的 key是enum类型,而value则可以是任意类型。
关于这个两个集合的使用就不在这里赘述,可以参考JDK文档。
Classpath*与classpath的区别
Spring可以通过指定classpath*:与classpath:前缀加路径的方式从classpath 加载文件,如bean的定义文件.classpath*:的出现是为了从多个jar文件中加载相同的文件.classpath:只能加载找到的第一个文件.
比如 resource1.jar中的package 'com.test.rs' 有一个
'jarAppcontext.xml' 文件,内容如下:
<bean name="ProcessorImplA" class="com.test.spring.di.ProcessorImplA" />
resource2.jar中的package 'com.test.rs' 也有一个 'jarAppcontext.xml' 文件,内容如下:
<bean id="ProcessorImplB" class="com.test.spring.di.ProcessorImplB" /> 通过使用下面的代码则可以将两个jar包中的文件都加载进来
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"classpath*:com/test/rs/jarAppcontext.xml");
而如果写成下面的代码,就只能找到其中的一个xml文件(顺序取决于jar包的加载顺序)
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"classpath:com/test/rs/jarAppcontext.xml");
classpath*:的使用是为了多个component(最终发布成不同的jar包)并行开发,各自的bean定义文件按照一定的规则:package+filename,而使用这些component的调用者可以把这些文件都加载进来.
classpath*:的加载使用了classloader的 getResources() 方法,如果是在不同的J2EE服务器上运行,由于应用服务器提供自己的classloader实现,它们在处理jar文件时的行为也许会有所不同。
要测试 classpath*: 是否有效,可以用classloader从classpath中的jar文件里加载文件来进行测试:
getClass().getClassLoader().getResources("<someFileInsideTheJar>") 。
(上面的例子是在sun的jre中运行的状态)
Servlet 3.0 实战:异步Servlet 与Comet 风格应用程序/blog/1189209
简介: 自JSR 315 规范(即Servlet 3.0)的草案公开发布以来,最新一代Servlet 规范的各种新特性被越来越多的开发人员所关注。
规范中提到的一系列高级目标:如可插拔的Web 框架、便捷开发特性、增强安全性支持等都令人期待。
但其中关注程度最高的,毫无疑问是异步Servlet。
本文将详细介绍Comet 风格应用的实现方式,以及Servlet 3.0 中的异步处理特性在Comet 风格程序中的实际应用。
概述
作为Java EE 6 体系中重要成员的JSR 315 规范,将Servlet API 最新的版本从2.5 提升到了3.0,这是近10 年来Servlet 版本号最大的一次升级,此次升级中引入了若干项令开发人员兴奋的特性,如:
∙可插拔的Web 架构(Web framework pluggability)。
∙通过Annotations 代替传统web.xml 配置文件的EOD 易于开发特性(ease of development)。
∙Serlvet 异步处理支持。
∙安全性提升,如Http Only Cookies、login/logout 机制。
∙其它改进,如文件上传的直接支持等。
其中,在开源社区中讨论得最多的就是Servlet 异步处理的支持,所谓Servlet 异步处理,包括了非阻塞的输入/输出、异步事件通知、延迟request 处理以及延迟response 输出等几种特性。
这些特性大多并非JSR 315 规范首次提出,譬如非阻塞输入/输出,在Tomcat 6.0 中就提供了Advanced NIO 技术以便一个Servlet 线程能处理多个Http Request,Jetty、GlassFish 也曾经有过类似的支持。
但是使用这些Web 容器提供的高级特性时,因为现有的Servlet API 没有对这类应用的支持,所以都必须引入一些Web 容器专有的
类、接口或者Annotations,导致使用了这部分高级特性,就必须与特定的容器耦合在一起,这对很多项目来说都是无法接受的。
因此JSR 315 将这些特性写入规范,提供统一的API 支持后,这类异步处理特性才真正具备广泛意义上的实用性,只要支持Servlet 3.0 的Web 容器,就可以不加修改的运行这些Web 程序。
JSR 315 中的Servlet 异步处理系列特性在很多场合都有用武之地,但人们最先看到的,是它们在“服务端推”(Server-Side Push)方式—— 也称为Comet 方式的交互模型中的价值。
在JCP(Java Community Process)网站上提出的JSR 315 规范目标列表,关于异步处理这个章节的标题就直接定为了“Async and Comet support”(异步与Comet 支持)。
本文将详细介绍Comet 风格应用的实现方式,以及Servlet 3.0 中的异步处理特性在Comet 风格程序中的实际应用。
经典Request-Response 交互模型的突破
“Comet 技术”、“服务端推技术(Server-Side Push)”、“反向Ajax 技术”这几个名称说的是同一件事情,可能您已经听说过其中的一项或者几项。
但没听说过也没有关系,一句话就足以表达它们全部的意思:“在没有客户端请求的情况下,服务端向客户端发送数据”。
这句话听起来很简单很好理解,但是任何一个长期从事B/S 应用程序开发的程序都清楚,这实现起来并不简单,甚至很长一段时间内,人们认为这是并不可能的。
因为这种做法完全不符合传统基于HTTP 协议的交互思想:只有基于Socket 层次的应用才能做到Server 和Client 端双方对等通讯,而基于HTTP 的应用中,Server 只是对来自Client 的请求进行回应,不关心客户端的状态,不主动向客户端请求信息,因此Http 协议被称为无状态、单向性协议,这种交互方式称为Request-Response 交互模型。
无状态、单向的经典Request-Response 交互模型有很多优点,譬如高效率、高可伸缩等。
对于被动响应用户请求为主的应用,像CMS、MIS、ERP 等非常适合,但是对于另外一些需要服务端主动发送的需求,像聊天室(用户不发言的时候也需要把其它用户的发言传送回来)、日志系统(客户端没有请求,当服务端有日志输出时主动发送到客户端)则处理起来很困难,或者说这类应用根本不适合使用经典的Request-Response 交互模型来处理。
当“不适合”与“有需求”同时存在时,人们就开始不断寻找突破这种限制的方法。
Comet 实现的方法
简单轮询
最早期的Web 应用中,主要通过JavaScript 或者Meta HTML 标签等手段,定
时刷新页面来检测服务端的变化。
显然定时刷新页面服务端仍然在被动响应客户端
的请求,只不过客户端的请求是连续、频繁的,让用户看起来产生有服务端自动将
信息发过来的错觉。
这种方式简单易行,但缺陷也非常明显:可能大部分请求都是
无意义的,因为服务端期待的事件没有发生,实际上并没有需要发送的信息,而不
得不重复的回应着页面上所有内容给浏览器;另外就是当服务端发生变化时,并不
能“实时”的返回,刷新的间隔太短,产生很大的性能浪费,间隔太长,事件通知又可能晚于用户期望的时间到达。
当绝大部分浏览器提供了XHR(XmlHttpRequest)对象支持后,Ajax 技术出现并迅速流行,这一阶段做的轮询就不必每次都返回都返回整个页面中所有的内容,如
果服务端没有事件产生,只需要返回极少量内容的http 报文体。
Ajax 可以节省轮询传输中大量的带宽浪费,但它无法减少请求的次数,因此Ajax 实现的简单轮询
仍然有轮询的局限性,对其缺陷只能一定程度缓解,而无法达到质变。
∙长轮询(混合轮询)
长轮询与简单轮询的最大区别就是连接时间的长短:简单轮询时当页面输出完连接
就关闭了,而长轮询一般会保持30 秒乃至更长时间,当服务器上期待的事件发生,将会立刻输出事件通知到客户端,接着关闭连接,同时建立下一个连接开始一次新
的长轮询。
长轮询的实现方式优势在于当服务端期待事件发生,数据便立即返回到客户端,期
间没有数据返回,再较长的等待时间内也没有新的请求发生,这样可以让发送的请
求减少很多,而事件通知的灵敏度却大幅提高到几乎是“实时”的程度。
∙Comet 流(Forever Frame)
Comet 流是按照长轮询的实现思路进一步发展的产物。
令长轮询将事件通知发送回客户端后不再关闭连接,而是一直保持直到超时事件发生才重新建立新的连接,这
种变体我们就称为Comet 流。
客户端可以使用XmlHttpRequest 对象中的
readyState 属性来判断是Receiving 还是Loaded。
Comet 流理论上可以使用一
个链接来处理若干次服务端事件通知,更进一步节省了发送到服务端的请求次数。
无论是长轮询还是Comet 流,在服务端和客户端都需要维持一个比较长时间的连接状态,这一点在客户端不算什么太大的负担,但是服务端是要同时对多个客户端服务的,按照经典Request-Response 交互模型,每一个请求都占用一个Web 线程不释放的话,Web 容器的线程则会很快消耗殆尽,而这些线程大部分时间处于空闲等待的状态。
这也就是为什么Comet 风格服务非常期待异步处理的原因,希望Web 线程不需要同步的、一对一的处理客户端请求,能做到一个Web 线程处理多个客户端请求。
实战Servlet 异步处理
当前已经有不少支持Servlet API 3.0 的Web 容器,如GlassFish v3、Tomcat 7.0、Jetty 8.0 等,在本文撰写时,Tomcat 7 和Jetty 8 都仍然处于测试阶段,虽然支持Servlet 3.0,但是提供的样例代码仍然是与容器耦合的NIO 实现,GlassFish v3 提供的样例(玻璃鱼聊天室)则是完全标准的Servlet 3.0 实现,如果读者需要做找参考样例,不妨优先查看GlassFish 的example 目录。
本文后一部分会提供另外一个更具备实用性的例子
“Web 日志系统”作为Servlet API 3.0 的实战演示进行讲解。
Web 日志系统实战
Apache Log4j 是当前最主流的日志处理器,它有许多不同的Appender 可以将日志输出到控制台、文件、数据库、Email 等等。
在大部分应用中用户都不可能查看服务器的控制台或者日志文件,如果能直接在浏览器上“实时”的查看日志将会是给开发维护带来方便,在本例中将实现一个日志输出到浏览器的Appender 实现。
清单 1. Log4j 异步Web Appender
上面是Appender 类的代码模版,派生自org.apache.log4j.WriterAppender,Log4j 默认提供的所有Appender 都从此类继承,子类代码执行的逻辑仅仅是告知WriterAppender 如何获取Writer。
而我们最关心的如何异步将日志信息输出至浏览器,则在AsyncContextQueueWriter 中完成。
清单2:异步上下文队列Writer
这个类是Web 日志实现的关键类之一,它继承至Writer,实际上是一组Writer 的集合,其中包含至少一个默认Writer 将数据输出至控制台,另包含零至若干个由
Queue<AsyncContext> 所决定的Response Writer 将数据输出至客户端。
输出过程中,控制台的Writer 是同步的直接输出,输出至http 客户端的则由线程notifierRunnable 进行异步输出。
具体实现方式是信息放置在阻塞队列MESSAGE_QUEUE 中,子线程循环时使用到这个队列的take() 方法,当队列没有数据这个方法将会阻塞线程直到等到新数据放入队列为止。
我们在Log4j.xml 中修改一下配置,将Appender 切换为WebLogAppender,那对Log4j 本身的扩展就算完成了:
清单3:Log4j.xml 配置
接着,建立一个支持异步的Servlet,目的是每个访问这个Servlet 的客户端,都在ASYNC_CONTEXT_QUEUE 中注册一个异步上下文对象,这样当有Logger 信息发生时,就会输出到这些客户端。
同时,将建立一个针对这个异步上下文对象的监听器,当产生超时、错误等事件时,将此上下文从队列中移除。
清单4:Web 日志注册Servlet
服务端处理到此为止差不多就结束了,我们再看看客户端的实现。
其实客户端我们直接访问这个Servlet 就可以看到浏览器不断的有日志输出,并且这个页面的滚动条会一直持续,显示http 连接并没有关闭。
为了显示,我们还是对客户端进行了包装,通过一个隐藏的frame 去读取WebLogServlet 发出的信息,既Comet 流方式实现。
清单5:客户端页面
清单6:客户端引用的application.js
为了模拟日志输出,我们读取了一个已有的日志文件,将内容调用Logger 输出到浏览器,读者在调试时直接运行源码包中的TestServlet 即可,运行后整体效果如下所示:
图 1. 运行效果
结束语
Comet 的出现为Web 交互带来了全新的体验,而Servlet 3.0 和异步IO 则为Comet
实现过程中服务端Web 线程占用的问题提供了规范的解决方案。
随着各种支持Servlet 3.0 容器的出现,Comet 的应用将越来越频繁,目前开发Comet 应用还是具有一定的挑
战性,但随着需求推动技术的发展,相信Comet 的应用会变得和AJAX 一样普及。
逻辑与/或和短路与/或的区别
What will happen when you attempt to compile and run the following code? int Output = 10;
boolean b1 = false;
if((b1 == true) && ((Output += 10) == 20)){
System.out.println("We are equal " + Output);
}else{
System.out.println("Not equal! " + Output);
}
A. Compilation error, attempting to perform binary comparison on logical data type.
B. Compilation and output of "We are equal 10".
C. Compilation and output of "Not equal! 20".
D. Compilation and output of "Not equal! 10".
逻辑操作符:&(与运算),^(异或运算),|(或运算)。
短路逻辑操作符:&&(并且),||(或者).
短路与/或运算符和逻辑与/或一样可以实现逻辑运算,但是此时有一个重要的区别:用逻辑与/或运算时,不管操作符两边的条件表
达式成不成立,它都要进行运算判断,而短路与/或运算不一样了,如果通过左侧的操作数就可以进行它们需要的判断,那么它就不会
再计算右侧的操作数了,请看下面的例子:
……
double value=0;
if(value!=0 && 1/value<1000){
System.out.println("The value is not too small.");
}
else{
System.out.println("The value is too small.");
}
……
运行结果:
The value is too small.
结果分析:
照理说应会出现除数为0的错误,但由于条件逻辑操作符是短路操作符,显然,value!=0条件不成立,立即就可作出判断应执行else
后的语句,所以它就不再会运算判断1/value<1000了.如果不懂请再看一例:
......
double int1=0,int2=1,int3=1;
if(int1!=0 & (int2=2)==1){
}
System.out.println("int2="+int2);
if(int1!=0 && (int3=2)==1){
}
System.out.println("int3="+int3);
......
运行结果:
int2=2.0
int3=1.0
&&当前一个逻辑判断为false时,后面的判断是不执行的
老猪(43284683) 11:39:27
与之相应的|| 当前一个逻辑判断为true时,后面的判断也是不执行的。