??xml version="1.0" encoding="utf-8" standalone="yes"?>
IE
GET /mail HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon)
Host: mail.google.com
Connection: Keep-Alive
Cookie:
gmailchat=killvin.liu@gmail.com/519974
; PREF=ID=d68c481e542af276:NW=1:TM=1151742225:LM=1151742225:S=2qbdhg0_z3i-OAbW; SID=DQAAAG8AAACEdcjD2IZMNqZVatDbD62X8_U18oJuTVQc9XZUJi7MgCkM8sggJ8M5npZ35GXjdalT2o8QWPUve04tepy61MPv4v_EpILafg3JdIf8AFjD91aMT0tI5gb763FouV3e_2-C364HDO5Qzb4P4gjjgpHC
Firefox
GET /mail HTTP/1.1
Host: mail.google.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
我们可以注意刎ͼ如果用户关闭了浏览器的Cookie选项Q在Firefox中对于新的请求是包含Cookie的信息的Q然而IE却恰恰相反!q也q接用IE览一些网站所D的Cookie校验p|问题Q比如即使用户在使用q程中突然关闭CookieQ依然可以自q讉K|站的各Ҏ务)Q进一步,如果某个|站是读取依靠Cookie中的信息来验证用?其是那U保存客户信息的提示)Q即使这个用L开或者关闭窗口,M一个后来的人都可以L的浏览这个用LU有信息Q这是Cookie的最大的问题所在,当然q是另外的话题,不属于本ơ讨论的范畴Q这一ơ要说的?/font>
如何避免IE览器下Q用户关闭Cookie的问题?br />
有一个思\Q经q测试我们发现IE览器只是在首次面h的时候才会去dCookie的|所以,Z避免IE览器关闭Cookie的问题,可以在用戯求某个链接的时候,先将用户的Cookie存放在某处,q清I此时所有的Cookie|再次的请求页面,而这样做的目的就是强qIEd盘上的CookieQ如果此时用户关闭了CookieQ就不会在请求的头信息中看到Cookie信息Q如果没有关闭Cookie,可以放心的原先的Cookie写回Reponse对象?br />
只是不知道Google的网站是否也是按照这个思\去解x问题的?
]]>
1。即使你提高了浏览器的隐U登讎ͼ在第一ơ打开H口的时候,你获取不CQ何的Cookies对象Q很昄的结果)Q然而当你再ơ刷新本面的,Cookie此时会奇q般的出玎ͼ而在Firefox览器中按照以上的步骤,是不会出现这L情况的?br />
2。不仅如此,你还可以透过Action的处理,多次的往Cookie中增加Cookie的数量(当然在Action中你依然可以自由的获取到Cookieq个数组Qƈ且不为空Q,然而让人匪h思的是在Cookie的存攄录下你是扑֯不到M的蛛丝马q的。而在Firefox没有出现以上的情c?br />
Q解?br />1。在首次q入面时查询客L的CookieQ如果不存在则警告用Pq要求再ơ的登陆?br />2。在用户登陆后,如果更改了浏览器的隐U别,对于Firefox标准的浏览器Q此时肯定不会再扑ֈCookie数组对象了,你需要做的仅仅只是将面调{到登陆窗口;而在IE下就非常的麻烦了甚至无法解决Q因Z依然可以讉K到原来的Cookie数组|Q比如,用IE在CSDN登陆后提高隐U别,你依然可以登陆到其他的服务区域)此时没有什么好的办法,不过Google解决了这L问题Q只是不知道如何解决的?/strong>
IE在处理Frame标记的问?br />1。如果你在某个页面中嵌入了Frame标签Qƈ且希望与q个嵌入的页面共享某些存攑֜Session中的数据Q此时你需要将外部的sessionId传入到frame标记的页面中。然而在IE中你可能q不能完全的享受q样的逻辑Q原因在于IE对于嵌入的页面不会自动的传递sessionIdQ也怽y可以Q也怸行,也就是说完全是在IE?掌控"之下。而在Firefox没有出现q样的情c?br />
Q解?br />为嵌入的面中所有的链接增加sessionId参数?br />
最好的办法是Q说服客户用标准的览器Firefox!
message |
By default the tag will retrieve the request scope bean it will iterate over from the |
也就是说在将message讄为trueӞ会去request中寻找Globals.MESSAGE_KEY所代表的beanQ然而我们在具体的Action使用ActionMessagescȝ时候往往是这L
ActionMessages messages = getErrors(request);
messages.add(ActionMessages.GLOBAL_MESSAGE , new ActionMessage(key , value0));
saveMessages(request,messages);
而往往困扰人的在于ؓ什么要lmessages中放入名UCؓ"ActionMessages.GLOBAL_MESSAGE"的ActionMessage对象Q而且q需要再ơ的调用saveErrors(request,messages)ҎQ?/strong>
首先要说明的是你为ActionMessage起Q何的名称都没有关p,因ؓActionMessages本nl持着一个HashMapQ而参数property是q个HashMap中的key|如果不存在则会徏立相应的key,q将需要保存的ActionMessage对象存入到这个key所对应的List中?br /> public void add(String property, ActionMessage message) {
ActionMessageItem item = (ActionMessageItem) messages.get(property);
List list = null;
if (item == null) {
list = new ArrayList();
item = new ActionMessageItem(list, iCount++, property);
messages.put(property, item);
} else {
list = item.getList();
}
list.add(message);
}
至于Z么一定要调用saveMessages(request,messages)Q看看它具体的实现逻辑清楚了
protected void saveMessages(
HttpServletRequest request,
ActionMessages messages) {
// Remove any messages attribute if none are required
if ((messages == null) || messages.isEmpty()) {
request.removeAttribute(Globals.MESSAGE_KEY);
return;
}
// Save the messages we need
request.setAttribute(Globals.MESSAGE_KEY, messages);
}
再对比前面介l的messagesPresent标签的用,是不是就清楚了呢Q原来它是将ActionMessages对象保存在request中,q且名称是Globals.ERROR_KEYQ从而ؓtag的顺利解析铺q了道\。当然按理你可以选择这L对象攄在Q何的scope中,但Action只是提供了request , session两种ScopeQ不qpage , application不经怋用,可以理解Q但不提供相应的l构׃太好了)
至于messagesPresent标签是如何在scope中寻找ActionMessages对象
org.apache.struts.taglib.logic.MessagesPresentTag
protected boolean condition(boolean desired) throws JspException {
ActionMessages am = null;
String key = name;
if (message != null && "true".equalsIgnoreCase(message)){
key = Globals.MESSAGE_KEY;
}
try {
am = TagUtils.getInstance().getActionMessages(pageContext, key);
} catch (JspException e) {
TagUtils.getInstance().saveException(pageContext, e);
throw e;
}
Iterator iterator = (property == null) ? am.get() : am.get(property);
return (iterator.hasNext() == desired);
}
org.apache.struts.taglib.TagUtils
public ActionErrors getActionErrors(PageContext pageContext, String paramName)
throws JspException {
ActionErrors errors = new ActionErrors();
Object value = pageContext.findAttribute(paramName);
if (value != null) {
try {
if (value instanceof String) {
errors.add(
ActionMessages.GLOBAL_MESSAGE,
new ActionMessage((String) value));
} else if (value instanceof String[]) {
String keys[] = (String[]) value;
for (int i = 0; i < keys.length; i++) {
errors.add(
ActionMessages.GLOBAL_MESSAGE,
new ActionMessage(keys[i]));
}
} else if (value instanceof ActionErrors) {
errors = (ActionErrors) value;
} else {
throw new JspException(
messages.getMessage(
"actionErrors.errors",
value.getClass().getName()));
}
} catch (JspException e) {
throw e;
} catch (Exception e) {
log.debug(e, e);
}
}
return errors;
}
PageContext中的findAttribute会帮你在scope中寻扑UCؓGlobals.MESSAGE_KEY的ActionMessage对象?br />
注意
虽然Struts已经声明Q不推荐使用ActionErrors & ActionError对象Q但在一些遗留的pȝ中,依然q是可以看到其媄子,所以如果你的系l不q属于这L两种混合pȝQ有以下的几U方法可以参?br />
1。两ơ调用messagesPresentQ如?br /><!-- Print ActionErrors Object -->
<logic:messagesPresent>
<html:messages id="msg" message="true">
<div class="success">
<bean:write name="msg"/>
</div><br/>
</html:messages>
</logic:messagesPresent>
<!-- Print ActionMessages Object -->
<logic:messagesPresent message="true">
<html:messages id="msg" message="true">
<div class="success">
<bean:write name="msg"/>
</div><br/>
</html:messages>
</logic:messagesPresent>
2.分别使用<html:messages> <html:errors>标签Q当然在老系l中需要调用Action的saveErrorsҎQ而在新的应用中要调用saveMessagesҎ?/font>
3.更换所有的ActionErrors为ActionMessages,q将所有调用saveErrors的地Ҏ换成saveMessagesQƈ?lt;html:errors>标签相应的更换成<html:messages message="true"> Q?推荐Q?/font>
从开发项目的cd角度看javaq_
ZB/Sl构的系l,在这个方向上的竞争是Ȁ烈的Q有专注于此的LAMPQLinux + Apache + Mysql + PhpQ?也有刚刚兴v的RailsQRuby FrameworksQ甚xL快速开发的ASP.NET;当然了java在这个领域里的MVC框架数都C完,比如Struts . Webwork{,然而即便是如此Q选择java作ؓ开发的理由也是不充分的Q因为在q个梯队里java多排名最后?/p>
ZC/Sl构的系l,在这个方面java昄没有考虑周到Q面对VB 、DELPHI、vcq些个如g虎的快速开发IDEQJAVA实在是显得异常的淡薄Q即使你扑ֈ了一个可以匹敌这些个ide的工P面对W三方的lg又会成ؓ一大障,所以java在这个方面又一ơ的输了?/p>
从java所的特性角度看javaq_
java的重Ҏ业务逻辑Q(我以前也是如此坚信不U)可是谁有能够说别的语a不注重业务逻辑呢,业务逻辑只是一个抽象的概念Qjava只是依靠ejb提出了业务组件而已Q其他的语言在实C务逻辑的时候也可以包装成POJO的Ş式,看来q个观点也是p|的?/p>
java的是跨^台的优势Q这可以理解为初U的、商业的、忽悠h的词汇,面对众多动态语a如PythonQ在若干q_上的表现Qjava又如何来自己q方面的优势呢?p|
java支持分布式应用的目Q可W的a论,分布式根本不是值得炫耀的资本,在java之前的c/s目中何不是分布式的应用呢Q失?/p>
既然没有了这些个优势Q我们看看java到底q剩下些什么?对了其实是应用服务器!然而看qJ2EE WITHOUT EJB的读者肯定知道Spring所希望辑ֈ的目的,也就是脱d用服务器概念上的J2EE体系实现Q既然在作者的眼里APPLICATION SERVER只不q是一个忽悠h的词汇,那么M目都选择java作ؓ开发的依据昄是自找苦吃Q?br />
那么什么情况下攚w择java作ؓ开发的q_呢?
<1> 如果你真的遇C大型的系l开发Q务,恭喜你,你终于可以看到分布式对象、集的优势了?br /><2> 客户是一个java的忠实fans或者是sun、ibm的金牌合作伙伴之cȝQ选择java是不得已的,但记住ƈ不能证明java是最好的实现方式
<3> 如果你只惛_心业务逻辑的实玎ͼ对于事务、缓存、查扄服务的实现没有兴的话,倒是不妨考虑采用ejb的Ş式,当然前提是你不愿意在L合适的替代品的情况下?br /><4> 如果目q切的寻找某U框架的支持Q选择java是对的Q你有众多优U的、免费的、可扩展的、天才的框架可以选择Q更多的时候你是出于尴的境地Q因ZQ何一个都让你心动、而这L选择往往是最痛苦、和快乐的?/p>
正确的选择
<1>
条g: 如果目仅仅只是一个小型的|站pȝ
选择: LAMP、Rails
<2>
条g: 目规模中等
q且目的时间比较紧Q?br />目可以架构在windows的系l之上,
选择: .Net / Delphi
<3>
条g: 大型的系l,有支持分布式对象、集的要求Q或者SUN / IBM的金牌合作伙?; 惌L某种优秀的框架来解决问题
选择: java是不二的选择Q可是我想问一下,在现实中你能遇到q样的项目吗Q?/p>
所以,从实际的角度出发Q我们面对的99Q可能都是一些符合条?Q?的系l,而选择java实在是得不偿q。最后以一DCode Complete中的话来作ؓl束?/p>
每个E序员都有很多的工具Q但q不存在M一个能够适用于所有工作的工具Q因地制宜的选择正确工具是成有效~程的程序员的关键?/strong>
JUnit ?Java?语言事实上的 标准单元试库。JUnit 4 是该库三q以来最具里E碑意义的一ơ发布。它的新Ҏ主要是通过采用 Java 5 中的标记QannotationQ而不是利用子cR反或命名机制来识别测试,从而简化测试。在本文中,执着的代码测试h?Elliotte Harold ?JUnit 4 ZQ详l介l了如何在自q工作中用这个新框架。注意,本文假设读者具?JUnit 的用经验?/BLOCKQUOTE>JUnit ?Kent Beck ?Erich Gamma 开发,几乎毫无疑问是迄今所开发的最重要的第三方 Java 库。正?Martin Fowler 所_“在软g开发领域,从来没有如此少的代码vC如此重要的作用”。JUnit 引导q促q了试的盛行。由?JUnitQJava 代码变得更健壮,更可靠,bug 也比以前更少。JUnitQ它本n的灵感来?Smalltalk ?SUnitQ衍生了许多 xUnit 工具Q将单元试的优势应用于各种语言。nUnit (.NET)、pyUnit (Python)、CppUnit (C++)、dUnit (Delphi) 以及其他工具Q媄响了各种q_和语a上的E序员的试工作?/P>
然而,JUnit 仅仅是一个工兯已。真正的优势来自?JUnit 所采用的思想和技术,而不是框架本w。单元测试、测试先行的~程和测试驱动的开发ƈ非都要在 JUnit 中实玎ͼM比较 GUI 的编E都必须?Swing 来完成。JUnit 本n的最后一ơ更新差不多是三q以前了。尽它被证明比大多数框架更健壮、更持久Q但是也发现?bugQ而更重要的是QJava 不断在发展。Java 语言现在支持泛型、枚举、可变长度参数列表和注释Q这些特性ؓ可重用的框架设计带来了新的可能?/P>
JUnit 的停滞不前ƈ没有被那些想要废弃它的程序员所打|。挑战者包?Bill Venners ?Artima SuiteRunner 以及 Cedric Beust ?TestNG {。这些库有一些可圈可点的Ҏ,但是都没有达?JUnit 的知名度和市场占有䆾额。它们都没有在诸?Ant、Maven ?Eclipse 之类的品中hq泛的开即用支持。所?Beck ?Gamma 着手开发了一个新版本?JUnitQ它利用 Java 5 的新Ҏ(其是注释)的优势,使得单元试比v用最初的 JUnit 来说更加单。用 Beck 的话来说Q“JUnit 4 的主题是通过q一步简?JUnitQ鼓励更多的开发h员编写更多的试。”JUnit 4 管保持了与现有 JUnit 3.8 试套g的向后兼容,但是它仍然承诺是?JUnit 1.0 以来 Java 单元试斚w最重大的改q?/P>
注意Q?/B>该框架的改进是相当前沿的。尽?JUnit 4 的大轮廓很清晎ͼ但是其细节仍然可以改变。这意味着本文是对 JUnit 4 抢先看,而不是它的最l效果?/P>
]]>
以下是robbin的观?/STRONG>
如果说不使用Session Facade模式的话Q我认ؓEBq是一个很有意义的的东西,因ؓEB是唯一直接支持跨RMI的持久化Ҏ。但是由于EB的效率和减少跨RMI的网l调用的原因QEB已经完全被封装到SB的后面,EB的分布式调用的功能,EB的安全验证功能,EB的容器事务功能完全被前面的SBl做了,l果EB只剩下了唯一的ORM功能了,单就ORMq一Ҏ说EB实在是一个非帔R常糟p的东西。那么EBq有什么功能值得我非ȝ它不可呢Q?
?Session Bean + DAO + Hibernate 来取?Session Bean + Entity BeanQ不但能够极大降低Y件设计难度,软g开发难度,软g调试隑ֺ和Y仉|难度,而且q可以提高允许效率,降低g要求?
不要把EB直接拿来和Hibernate做比较,两者不是一个范畴的东西Q而应该整体比较两U方案:
Session Bean + DAO + Hibernate
Session Bean + Entity Bean
我找不出来第二方案有哪怕一Ҏ面能够比W一Ҏ好的?
CMP可以使用CMR来表C多表之间通过外键兌的关pR但是你仍然会遇到即使没有键兌的表仍然需要连接查询的情况Q这是一个非常普遍的现象?
如果是HibernateQ可以在HSQL里面定义outer joinQBMP也可以写JDBCQ而CMP没有M办法来解册问题Q除非你把需要的q接查询都定义ؓCMRQ但那样的话Q凡是有需要连接查询,或者有键关联的表都必须打在一个包里面。你如果不打在一个jar包里面,如果能够建立CMRQ不是我x在一个jar里面Q而是不得不放在一个jar里面。基本上CMPq是非常W拙的?
CMP的另一大缺Ҏ不能动态SQLQguty已经提到了,一个SQLp定义一个EJBFinderҎQ在~译的时候就定M。在实际应用中,l常会遇C定查询条g的查询,比如说用户在面上用下拉列表来选择查询的条Ӟ用户既有可能什么限制条仉不选,也有可能选择某几个条件。这时候你怎么办?假设有n个查询条Ӟ你要?C1n + C2n + C3n +...+ Cnn(C是组合公式的W合Qn是下标,1...n是上?个EJBFinderҎ才行Q很恐怖吧?
其实JDBC的PrepareStatement也不能很好的解决q个问题Q因为它是按?Q?q样的次序来set参数的。用Statement是肯定不行的Q会严重影响数据库,甚至会导致数据库down?我的实际l验)。但是Hibernatep决的不错Q因为它可以按照 :name q样的Ş式来讑֮SQL中的PlaceholderQ这样set参数可以按照参数名UC递,因ؓơ序不是ȝQ在E序里面很ҎҎ用户选择的查询条Ӟ动态的产生SQLQ动态的set参数了?
CMP2.0q有一个大问题是不支持order byQ当然你可以在Java里面对取出来的集合排序,但是速度和数据库里面排好序速度不在一个数量了。Hibernate不但可以order byQ还可以group byQhavingQ子查询Q真是没有办法比下去了?
其实对于动态SQL和排序问题,特定的App Server也可以做Q但那不是CMP2.0的规范Ş了,所以ؓ了可UL性,也不敢随便去用?
在项目开发时Q?开发和q行效率以及灉|性是非常重要的指标。由于Entity Bean天生是一U粗_度的用方式,q就必定使它在装载的时候有较长的响应时_也不能自如的支持懒装入的方式Q用成l粒度会使程序变得复杂,以及q程调用l粒度的entity bean是一U非常可怕的行ؓ, 太慢?
Hibernate正好满开发和q行效率以及灉|性,说来说去Q它可以U做一个OO化的JDBC, q样大家׃会对Hibernate产生误解及恐惧心理。它支持_细两种_度方式Q运用v来灵z自如,前提是你必知道如何用,一个entity bean 实现要NU重复的Ҏ, such as ejbRemove,ejbstore,ejb...., 光类也有一大堆Q象Home Interface, Romote Interface..., Primary class if necessary. Hibernate只需要一个就行了?
CMP在进行O/R Mapping斚w只是做了最基础的工作而已Q完全用CMP做数据层Q会发现你在把数据库应该做的工作全部都搬到App Server里面来重新实C遍,有这必要吗?
CMP是把EJBQL写死?SPAN style="COLOR: #ffa34f">ejb-jar.xml里面的,所以n个条件就需?c0n+c1n+...cnn )2的nơ方个EJBFinderҎQ简直没有办法说?
JDBC实现PrepareStatement的动态SQL构造不是不能够Q而是非常ȝQ需要写一个非帔R常大的if elseif else嵌套的判断?
Hibernate实现h特别单,Q其实OJB也实CPrepareStatement的动态SQL构造)q本wƈ不复杂,但是需要你多写些代码而已Q由于CMP把EJBQL写死在配|文仉面了Q你q选择的余地都没有?/SPAN>
Class.forName("jdbc.DriverXYZ");
Connection con = DriverManager.getConnection(url,
"myLogin", "myPassword");
Class.forName(..)
method did. The most common answer you'll hear is that it loads the database driver, which, while technically true, is shallow. Where does it get loaded? How does it happen? And why?
To answer the question I started with the JavaDoc for the Class.forName() method. According to the documentation, the method:
... attempts to locate, load, and link the class or interfaceI wasn't perfectly clear on what "locate, load, and link" meant, so I did a little digging through the Java Language Specification. According to chapter 12 of the JLS:
Loading refers to the process of finding the binary form of a class or interface type with a particular name, perhaps by computing it on the fly, but more typically by retrieving a binary representation previously computed from source code by a compiler, and constructing, from that binary form, a Class object to represent the class or interface.Next, again according to the JLS, it must be transformed from it's binary representation to something the Java virtual machine can use, this process is called linking. Finally, the class is initialized, which is the process that executes the static initializer and the initializers for static fields declared in the class.
So then back to the original problem, when Class.forName() is called with an argument like this:
Class.forName("org.gjt.mm.mysql.Driver");
the classloader attempts to load and link the Driver
class in the "org.gjt.mm.mysql" package and if successful, the static initializer is run. The MySQL Driver
(download the source code) static initializer looks like this:
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
So it calls a static method in the java.sql.DriverManager class which apparently registers a copy of itself when it loads.
So now I understand the where and the how, what about why? To understand the why you have to look at the next line in the initial code example:
Connection con = DriverManager.getConnection(url,
"myLogin", "myPassword");
The DriverManager
class (view DriverManager source here) returns a database connection given a JDBC URL string, a username and a password. In order to create that connection, the DriverManager class has to know which database driver you want to use. It does that by iterating over the array (internally a Vector) of drivers that have registered with it (ie: the registerDriver(Driver driver)
method illustrated above) and calls the acceptsURL(url))
method on each driver in the array, effectively asking the driver to tell it whether or not it can handle the JDBC URL.
So there you have it. Class.forName explained.
q里有一份详l的参考资料:
关于Java栈与堆的思?http://www.javafan.net/article/20051123115654293.html
Here's a list of keywords in the Java language. These words are reserved ?you cannot use any of these words as names in your programs.
true
,false
, andnull
are not keywords but they are reserved words, so you cannot use them as names in your programs either.abstract | continue | for | new | switch
assert*** | default | goto* | package | synchronized
boolean | do | if | private | this
break | double | implements | protected | throw
byte | else | import | public throws
case | enum**** | instanceof | return | transient
catch | extends | int | short | try
char | final | interface | static | void
class | finally | long | strictfp** | volatile
const* | float | native | super | while
* not used
** added in 1.2
*** added in 1.4
**** added in 5.0
Key: strictfp**
使用对象Q类、方?/P>
自Java2以来QJava语言增加了一个关键字strictfpQ虽然这个关键字在大多数场合比较用Q但是还是有必要了解一下?/P>
strictfp的意思是FP-strictQ也是说精Q点的意思。在Java虚拟行Q点运时Q如果没有指定strictfp关键字时QJava的编译器以及q行环境在对点q算的表辑ּ是采取一U近g我行我素的行为来完成q些操作Q以致于得到的结果往往无法令你满意。而一旦用了strictfp来声明一个类、接口或者方法时Q那么所声明的范围内Java的编译器以及q行环境会完全依照Q点规范IEEE-754来执行。因此如果你惌你的点q算更加_Q而且不会因ؓ不同的硬件^台所执行的结果不一致的话,那就L关键字strictfp?/P>
你可以将一个类、接口以及方法声明ؓstrictfpQ但是不允许Ҏ口中的方法以及构造函数声明strictfp关键字,例如下面的代码:
1. 合法的用关键字strictfp
strictfp interface A {}
public strictfp class FpDemo1 {
strictfp void f() {}
}
2. 错误的用方?/P>
interface A {
strictfp void f();
}
public class FpDemo2 {
strictfp FpDemo2() {}
}
一旦用了关键字strictfp来声明某个类、接口或者方法时Q那么在q个关键字所声明的范围内所有Q点运都是精的Q符合IEEE-754规范的。例如一个类被声明ؓstrictfpQ那么该cM所有的Ҏ都是strictfp的?/P>
Keys: volatile
使用对象Q字D?BR>
介绍Q因为异步线E可以访问字D,所以有些优化操作是一定不能作用在字段上的。volatile有时
可以代替synchronized?BR>
KeysQ?FONT face="Courier New">transient
使用对象Q字D?/P>
介绍Q字D不是对象持久状态的一部分Q不应该把字D和对象一起串赗?/P>
记得当初参与某公司的ERP目中,接触q异常框架这个概念,可是gq没有感觉到当时技术经理提个概늚意义Q而且他也对这个概念似乎很"保守"Q虽然按照他的思\L行,但没有理解的概念再实施v来的时候L觉得?别扭"Q而如今面对自p设计咚咚了,不得不重新审视异常这个概念,JAVA异常的介l文章在|络上非常的,而对于如何构件J2EE的异常处理框架更昄E,于是׃使自己写下了q样的文章?/P>
本文只是自己的一些愚见,希望和大家相互学习。Email:Killvin@hotmail.com
概念
什么是异常Q?/P>
异常QexceptionQ应该是异常事gQexceptional eventQ的~写?BR>异常定义Q异常是一个在E序执行期间发生的事Ӟ它中断正在执行的E序的正常的指o?BR>当在一个方法中发生错误的时候,q个Ҏ创徏一个对象,q且把它传递给q行时系l。这个对象被叫做异常对象Q它包含了有关错误的信息Q这些信息包括错误的cd和在E序发生错误时的状态。创Z个错误对象ƈ把它传递给q行时系l被叫做抛出异常?BR>一个方法抛出异常后Q运行时pȝ׃试着查找一些方法来处理它。这些处理异常的可能的方法的集合是被整理在一LҎ列表Q这些方法能够被发生错误的方法调用。这个方法列表被叫做堆栈调用Qcall stackQ?/P>
q行时系l搜d含能够处理异常的代码块的Ҏ所h的堆栈。这个代码块叫做异常处理器,搜寻首先从发生的Ҏ开始,然后依次按着调用Ҏ的倒序索调用堆栈。当扑ֈ一个相应的处理器时Q运行时pȝ把异常传递给q个处理器。一个异常处理器要适当地考o抛出的异常对象的cd和异常处理器所处理的异常的cd是否匚w。异常被捕获以后Q异常处理器关闭。如果运行时pȝ搜寻了这个方法的所有的调用堆栈Q而没有找到相应的异常处理器?/P>
怎么设计异常框架
M的异帔R是Throwablec(Z不是接口Q?Q,q且在它之下包含两个字类Error / ExceptionQ而Error仅在当在Java虚拟Z发生动态连接失败或其它的定位失败的时候,Java虚拟机抛Z个Error对象。典型的易程序不捕获或抛出Errors对象Q你可能永远不会遇到需要实例化Error的应用,那就让我们关心一下Exception
Exception中比较重要的是RuntimeExceptionQ运行时异常Q当然这个名字是存在争议的,因ؓM的异帔R只会发生在运行时Q,Z么说q个cL很重要的呢?因ؓ它直接关pd你的异常框架的设计,仔细看RuntimeException
A method is not required to declare in its throws clause any subclasses of RuntimeException that might be thrown during the execution of the method but not caught.
Q可能在执行Ҏ期间抛出但未被捕L RuntimeException 的Q何子c都无需?throws 子句中进行声明?
也就是说你的应用应该不去“关心”(说不兛_是不服责ȝQ但只是你不应该试图实例化它的字c)RuntimeExceptionQ就如同你不应该兛_Error的生与处理一PRuntimeException描述的是E序的错误引h的,因该q序负担这个责任!Q?lt;B>从责任这个角度看Error属于JVM需要负担的责Q;RuntimeException是程序应该负担的责Q;checked exception 是具体应用负担的责Q</B>Q?/P>
那就有h会问Q那我该兛_什么!{案是除了Error与RuntimeExceptionQ其他剩下的异常都是你需要关心的Q而这些异常类l称为Checked Exception,至于Error与RuntimeException则被l称为Unchecked Exception.
异常的概念就q些了,即你在|络上搜索也׃q如此,是不是感觉到有点清晰又有Ҏp?那么怎么该如何在q样单薄而模p的概念下设计J2EE的异常框架呢Q?/P>
解决ҎQJ2EE异常框架
我们拿一个模拟的例子来说明异常框架的设计q程Q比如我们要对外提供doBusiness()q个业务Ҏ
public void doBusiness() throws xxxBusinessException
当客L调用q样的方法的时候应该这样处理异常(包括处理RuntimeException , checked exceptionQ?BR><B>CQ无论如何我们都不希望或者确切的说是不应该将RuntimeExceptionq样的异常暴露给客户的,因ؓ他们没有解决q个问题的责任!</B>
我们暂时Struts中的某个Action看作时客LQ其中doExecute(....)要调用doBusiness()q个Ҏ
public void doAction(......)
{
try
{
xxx.doBusiness();
}
catch(Exception e)
{
if(e instanceof RuntimeException)
{
// catch runtime exception
// 你可以在q里捕获到的RuntimeException
// 异帔R知l某个负责此E序的程序员Q让他知道他
// 自己犯了多么低的错误!
}else
{
//checked exception such as xxxBusinessException
//这L异常暴露l客hC?nbsp;
}
}
}
我们可以q样设计xxxBusinessException
public class xxxBusinessException extends ApplicationException
{
public xxxBusinessException(String s){
super(s);
};
import java.io.PrintStream;
import java.io.PrintWriter;
public class ApplicationException extends Exception {
/** A wrapped Throwable */
protected Throwable cause;
public ApplicationException() {
super("Error occurred in application.");
}
public ApplicationException(String message) {
super(message);
}
public ApplicationException(String message, Throwable cause) {
super(message);
this.cause = cause;
}
// Created to match the JDK 1.4 Throwable method.
public Throwable initCause(Throwable cause) {
this.cause = cause;
return cause;
}
public String getMessage() {
// Get this exception's message.
String msg = super.getMessage();
Throwable parent = this;
Throwable child;
// Look for nested exceptions.
while((child = getNestedException(parent)) != null) {
// Get the child's message.
String msg2 = child.getMessage();
// If we found a message for the child exception,
// we append it.
if (msg2 != null) {
if (msg != null) {
msg += ": " + msg2;
} else {
msg = msg2;
}
}
// Any nested ApplicationException will append its own
// children, so we need to break out of here.
if (child instanceof ApplicationException) {
break;
}
parent = child;
}
// Return the completed message.
return msg;
}
public void printStackTrace() {
// Print the stack trace for this exception.
super.printStackTrace();
Throwable parent = this;
Throwable child;
// Print the stack trace for each nested exception.
while((child = getNestedException(parent)) != null) {
if (child != null) {
System.err.print("Caused by: ");
child.printStackTrace();
if (child instanceof ApplicationException) {
break;
}
parent = child;
}
}
}
public void printStackTrace(PrintStream s) {
// Print the stack trace for this exception.
super.printStackTrace(s);
Throwable parent = this;
Throwable child;
// Print the stack trace for each nested exception.
while((child = getNestedException(parent)) != null) {
if (child != null) {
s.print("Caused by: ");
child.printStackTrace(s);
if (child instanceof ApplicationException) {
break;
}
parent = child;
}
}
}
public void printStackTrace(PrintWriter w) {
// Print the stack trace for this exception.
super.printStackTrace(w);
Throwable parent = this;
Throwable child;
// Print the stack trace for each nested exception.
while((child = getNestedException(parent)) != null) {
if (child != null) {
w.print("Caused by: ");
child.printStackTrace(w);
if (child instanceof ApplicationException) {
break;
}
parent = child;
}
}
}
public Throwable getCause() {
return cause;
}
}
?聪明"的读者肯定要问我那doBusiness()q个业务Ҏ该如何包装异常呢Q?/P>
public void doBusiness() throw xxxBusinessException
{
try
{
execute1(); // if it throw exception1
exexute2(); // if it throw exception 2
.... .....
}
catch (exception1 e1)
{
throw new xxxBusinessException(e1);
}
catch(exception2 e2)
{
throw new xxxBusinessException(e2);
}
........
}
也可以这?/P>
public void doBusiness() throw xxxBusinessException
{
try
{
execute1(); // if it throw exception1
exexute2(); // if it throw exception 2
.... .....
}
catch (Exception e)
{
// 注意很多应用在这里根本不判断异常的类型而一股脑的采?BR> // throw new xxxBusinessException(e);
// 而这样带来的问题是xxxBusinessException"吞掉?RuntimeException
// 从而将checked excption 与unchecked exception混在了一P
// 其实xxxBusinessException属于checked excpetion Q它Ҏ不应该也不能够理睬RuntimeException
if(! e instanceof RuntimeException) throw new xxxBusinessException(e);
}
}
ȝ
1。JAVA的异常分Zc? checked exception & unchecked excpetion
2。应用开发中产生的异帔R应该集成自Exception 但都属于checked excpetioncd
3。应用中的每一层在包装q传递异常的时候要qo掉RuntimeExceptionQ?BR> 4。从责Qq个角度看Error属于JVM需要负担的责Q;RuntimeException是程序应该负担的责Q;checked exception 是具体应用负担的责Q
5。无论如何我们都不希望或者确切的说是不应该将RuntimeExceptionq样的异常暴露给客户的,因ؓ他们没有解决q个问题的责任!
今天讨论的不是不是内部类的概念,而是具体使用的一个场景-如何在内部类中返回外部对?/P>
看一D代?/P>
import java.util.LinkedList;
import java.util.List;
public class OuterClass
{
private List listeners = new LinkedList();
public void addListeners(IListener listener)
{
this.listeners.add(listener);
}
private OuterClass outer = this; Q?Q?BR> private class InnterClass
{
public void publish()
{
//事件发布出?Q?Q?BR> for(int i=0;i < listeners.size();i++)
{
IListener listener = (IListener) listeners.get(i);
listener.receiveEvent(outer);
}
}
}
public void execute()
{
InnterClass in = new InnterClass(); Q?Q?BR> in.publish();
}
}
public interface IListener
{
public void receiveEvent(OuterClass obj);
}
你可能觉得这个例子很别扭Q在哪里让你觉得隑֏呢?其实问题的关键就在于接口IListener的定义,q里需要给receiveEventҎ传递的参数是外部对象!Q别Ȁ动,下面我会说明需要传递的一个场景)
场景
在一个GUIpȝ中,我们要在LWorkSpaceQWorkSpace实现了IListener接口Q上产生一颗树Q但树中的每个节点的产生Q绘图)是我们不知道的算法,pȝ只ؓ我们提供了一些绘囄接口Qƈq回元素的句柄!看来我们需?包装"一下这个绘囄句柄BrushQ其实我把它叫做W刷Q因为它只知道如??出图像来Q就q点本事Q)q对外提供节?STRONG>Nodeq样一个通用的类?/P>
此时Node与Brush的关pd很微妙了Q不q我们可以抛开q些外表Q看到Node与Brush其实是外部cM内部cȝ关系Q-W一步完成了Q确定了两者的关系
然而,事情没有q么单,Nodecdd理一些事Ӟ而这些事件理所当然只有Brush能够看懂Q而NodeҎ不知道这L事g处理q程Q现在有两个办法Q办法一Q让Node实现Brush所有的事gQ办法二Q把Brushq回回去Q让它来处理自己的事Ӟ看来办法二是个好LQ因为我可以不关心事件的U类Q-W二步完成了Q确定了事g处理的责?/STRONG>
q没完呢Q你肯定不希?STRONG>LWorkSpace面对的是l图的句?/STRONG>Brushq样的对象,相反你只希望WokSpace只知道Node的存在!IListener接口中receiveEventҎ的参数定义ؓOuterClass q此而来Q-W三步完成:接口的定?/STRONG>
public interface IListener
{
public void receiveEvent(OuterClass obj);
}
既然说清楚了q个问题Q应该比较清楚了吧?Q那改如何实现这样一个蹩脚而有无可奈何的设计呢Q让我们回忆一下内部类Q内部类拥有讉K外部cȝҎ与属性的权限
private OuterClass outer = this; Q?q个对外部类的引用就是ؓ内部cȝ讉K准备?/STRONG>
private class InnterClass
{
public void publish()
{
//事件发布出?nbsp;
for(int i=0;i < listeners.size();i++)
{
IListener listener = (IListener) listeners.get(i);
listener.receiveEvent(outer); Q?nbsp;q里不可以返回thisQ因为this代表的是内部c自?BR> }
}
参?/P>
Java Nested class http://blog.csdn.net/Killvin/archive/2006/01/10/574983.aspx
初识Java内部c? http://blog.csdn.net/killvin/archive/2006/01/10/574991.aspx