Vincent Jia 博客

to be a better man, to be a bad man.

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  29 随笔 :: 3 文章 :: 0 评论 :: 0 Trackbacks

2010年2月10日 #

2016年,收获了什么,失去了什么。 
博客没有写作。
国家大事件几多。
posted @ 2017-12-04 16:53 iLinux 阅读(208) | 评论 (0)编辑 收藏

The Collections Framework







The collections framework is a unified architecture for representing and manipulating collections, allowing them to be manipulated independently of the details of their representation. It reduces programming effort while increasing performance. It allows for interoperability among unrelated APIs, reduces effort in designing and learning new APIs, and fosters software reuse. The framework is based on fourteen collection interfaces. It includes implementations of these interfaces, and algorithms to manipulate them.
Overview
  • Overview - An overview of the Collections framework.
API Specification
  • API Reference - An annotated outline of the classes and interfaces comprising the collections framework, with links into the JavaDoc.
Tutorials and Programmer's Guides
  • Tutorial - A tutorial introduction to the collections framework with plenty of programming examples.
API EnhancementsMore Information
  • Design FAQ- Answers to frequently asked questions concerning the design of the collections framework.

From: http://docs.oracle.com/javase/6/docs/technotes/guides/collections/index.html
posted @ 2012-07-06 16:15 iLinux 阅读(263) | 评论 (0)编辑 收藏

API Enhancements

posted @ 2012-07-06 16:14 iLinux 阅读(272) | 评论 (0)编辑 收藏

LinkedHashSet是JDK 1.4中引入的新的集合类(LinkedHashMap也是同期引入)。 LinkedHashSet,顾名思义,就是在Hash的实现上添加了Linked的支持。对于LinkedHashSet,在每个节点上通过一个链表串联起来,这样,就可以保证确定的顺序。对于希望有常量复杂度的高效存取性能要求、同时又要求排序的情况下,可以直接使用LinkedHashSet。

它实现了Set接口。存入Set的每个元素必须是唯一的,因为Set不保存重复元素。但是Set接口不保证维护元素的次序(那里面的元素每次顺序如何确定?TODO)。Set与Collection有完全一样的接口Iterable,同时Set继承了Collection。

LinkedHashSet具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的顺序),于是在使用迭代器便利Set时,结果会按元素插入的次序显示。

需求如: 含多个(有重复)元素ArrayList,去除重复。

1, 可以使用如下略显冗余的代码:
 1 public static List removeDuplicateWithOrder(List list) {
 2         Set set = new HashSet();
 3         List newList = new ArrayList();
 4         for (Iterator iter = list.iterator(); iter.hasNext();) {
 5             Object element = iter.next();
 6             if (set.add(element))
 7                 newList.add(element);
 8         }
 9         return newList;
10     }
此方法有滥用set之嫌。

2, 我们也可以使用本文章中提及的LinkedHashSet:
return new ArrayList<T>(new LinkedHashSet<T>(list));
此方法,既利用set去除了重复,又使用linked保持住了原顺序。

3, 貌似apache commons lang中有专门去重复的集合工具。

这儿的链表操作是常量级的,这也是LinkedHashSet/LinkedHashMap比TreeSet/TreeMap性能更高的原因。当然,LinkedHashSet不是thread-safe的,在多线程环境下,需要进行同步包装:
Collections.synchronizedCollection(Collection);
or:
Collections.synchronizedSet(Set);
在使用LinkedHashSet的iterator()方法遍历元素时,如果其他线程有读取操作,也要进行同步,否则,就会抛出同其它fail-fast一样的由于删除或增加操作而引起的CurrentModificationException。


如上两种方法的效率比较,设为TODO,
1, 利用set.add(element)方法,本质是利用其contains()方法判断,而contains()的本质就是遍历。
JDK doc中写道:
More formally, adds the specified element e to this set if the set contains no element e2 such that (e==null ? e2==null : e.equals(e2)). If this set already contains the element, the call leaves the set unchanged and returns false. In combination with the restriction on constructors, this ensures that sets never contain duplicate elements.
2, 测试数据,可以使用数据量:1W,5W,10W,100W。

posted @ 2012-07-06 11:54 iLinux 阅读(6208) | 评论 (0)编辑 收藏

在当前的系统中,大量使用了非泛型模式的Collection、List、Map、HashMap、HashTable。
其关系、区别在于。
posted @ 2012-06-29 17:50 iLinux 阅读(253) | 评论 (0)编辑 收藏

在美国得克萨斯州的一个风雪交加的夜晚,一位名叫克雷斯的年轻人因为汽车“抛锚”被困在郊外。正当他万分焦急的时候,有一位骑马的男子正巧经过这里。见此情景,这位男子二话没说便用马帮助克雷斯把汽车拉到了小镇上。 事后,当感激不尽的克雷斯拿出不菲的美钞对他表示酬谢时,这位男子说:“这不需要回报,但我要你给我一个承诺,当别人有困难的时候,你也要尽力帮助他人。”于是,在后来的日子里,克雷斯主动帮助了许许多多的人,并且每次都没有忘记转述那句同样的话给所有被他帮助的人。 许多年后的一天,克雷斯被突然暴发的洪水困在了一个孤岛上,一位勇敢的少年冒着被洪水吞噬的危险救了他。当他感谢少年的时候,少年竟然也说出了那句克雷斯曾说过无数次的话:“这不需要回报,但我要你给我一个承诺……” 克雷斯的胸中顿时涌起了一股暖暖的激流:“原来,我穿起的这根关于爱的链条,周转了无数的人,最后经过少年还给了我,我一生做的这些好事,全都是为我自己做的!”  当您有幸看到此消息时,请转发给自己的朋友亲人。我相信有更多的人需要我们的帮助, 正义会传染 邪恶也是如此, 为现在的别人做善事也是为了将来的自己。
传递温暖,拒绝冷漠。
  1、如果钱还宽裕,别养二奶,偷偷养几个贫困山区的学生,你心里一定会觉得舒坦;
  2、遇到夜里摆地摊的,能买就多买一些,别还价,东西都不贵。家境哪怕好一点,谁会大冷天夜里摆地摊;
    遇到学生出来勤工俭学的,特别是中学生、小姑娘,她卖什么你就买点。如果她不是家庭困难,出来打工也需要勇气的,鼓励鼓励她吧;   
  3、捡到钱包就找找失主。如果你实在缺钱就把现金留下,打电话告诉失主就说你在厕所里捡到的。把信用卡、身份证、驾驶执照还给人家,一般别人也不会在乎钱了。把人家的地址记在你的笔记本上,以后发达了去找人家道个歉,把钱还给人家;   
  4、遇到问路的,碰巧你又知道那个地址,就主动告诉一声。别不好意思,没有人笑话你;    
  5、如果丢的垃圾里有碎玻璃、大头针、刀片等,请用胶带把它们缠裹一下,并尽量多缠几层。这样就降低了保洁人员或者捡垃圾者被伤害的概率。他们大都是没有医保的弱势群体,体贴体贴他们吧,好人会有好报的。
  6、遇到迷路的小孩和老头老太,能送回家送回家,不能送回家的送上车、送到派出所也行。替老人或小孩打个电话再走,反正你也不缺那两个电话费;    
  7、雨雪的时候、天冷的傍晚,遇到卖菜的、卖水果的,剩的不多了又不能回家,能全买就全买,不能全买就买一份,反正吃什么也是吃,买下来让人早点回家;   
  8、上车遇到老弱病人、孕妇,让座的时候别动声色,也别大张旗鼓。站起来用身体挡住其他人,留出空位子给需要的人,然后装作下车走远点。人太多实在走不远,人家向你表示谢意的时候微笑一下;   
  9、不要对有精神信念的人用猥亵言词,要知道中国人缺就缺在没有信仰。这世界什么都在变,什么都不可全信,唯有信念不变、不动、永恒;   
  10、如果您的时间还宽裕,把这几句话转几个群,网上很多人看,转了心里舒坦。
  11、一般情况,看完这段文章而且主动到各个群里转发的人,都还是遗留着传统美德的中国好人
posted @ 2012-06-27 23:08 iLinux 阅读(245) | 评论 (0)编辑 收藏

在文章http://www.blogjava.net/aoxj/archive/2012/06/16/380926.html中,看到案例,++符号并不是原子操作,
posted @ 2012-06-27 23:08 iLinux 阅读(224) | 评论 (0)编辑 收藏

李小龙传奇 - 15 Kick-ass Bruce Lee quotes
http://www.slideshare.net/thepresentationdesigner/15-kickass-bruce-lee-quotes
posted @ 2012-06-25 17:33 iLinux 阅读(224) | 评论 (0)编辑 收藏

OoO
http://www.bbc.co.uk/worldservice/learningenglish/language/wordsinthenews/2011/08/110803_witn_korea.shtml
http://developer.51cto.com/col/461/
http://www.google.com/search?q=runtimeexception&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:zh-CN:official&client=firefox-a#sclient=psy&hl=en&client=firefox-a&rls=org.mozilla:zh-CN%3Aofficial&source=hp&q=spring3+%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86&pbx=1&oq=spring3+%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86&aq=f&aqi=&aql=&gs_sm=e&gs_upl=316376l316376l4l316608l1l1l0l0l0l0l0l0ll0l0&fp=1&biw=1280&bih=769&bav=on.2,or.r_gc.r_pw.,cf.osb&cad=b
http://www.infoq.com/cn/news/2011/01/git-adventures-1
http://www.kernel.org/pub/software/scm/git/docs/gittutorial.html
http://www.linuxeden.com/forum/thread-191912-1-1.html
http://books.slashdot.org/story/04/11/12/2042249/How-Tomcat-Works
http://static.springsource.org/spring/docs/3.1.0.M2/spring-framework-reference/html/orm.html#orm-hibernate
http://stackoverflow.com/questions/tagged/spring?sort=faq&pagesize=15
http://xiaolinjava.iteye.com/blog/684292
http://www.donews.com/original/201112/1011333.shtm
http://www.readwriteweb.com/archives/top_10_social_web_products_of_2011.php
http://www.readwriteweb.com/archives/the_10_biggest_web_news_stories_of_2011.php
http://blog.csdn.net/buoll/article/details/1851149
http://www.blogjava.net/masen/articles/118701.html
http://www.baidu.com/s?bs=org.springframework.jdbc.datasource.DriverManagerDataSource&f=8&rsv_bp=1&wd=tomcat+jndi&inputT=2640
http://home.51.com/xiaohei267/diary/item/10048051.html
http://blog.csdn.net/wzl002/article/details/5969635
http://www.baidu.com/s?bs=spring+controller+%D7%AA%B7%A2&f=8&rsv_bp=1&wd=spring+3.0+%B4%EE%BD%A8&inputT=7004
http://book.ifeng.com/lianzai/detail_2010_08/25/2309143_11.shtml
http://www.learnamericanenglishonline.com/
http://bulo.hjenglish.com/app/menu/558/
http://bulo.hjenglish.com/menu/zzk?langs=en
posted @ 2011-12-30 15:46 iLinux 阅读(295) | 评论 (0)编辑 收藏

沃夏克的《自新大陆交响曲》 卡拉扬指挥



posted @ 2011-12-30 03:45 iLinux 阅读(202) | 评论 (0)编辑 收藏

“开-闭”原则 (Open-Closed principle, OCP)

 

一个软件实体应当对扩展开放,对修改关闭。

Software entities should be open for extension, but closed for modification.

在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展。

 

“可变性的封装原则”从工程的角度讲解了如何实现“开-闭”原则。

   “可变性的封装原则”意味着两点:

1.一种可变性不应当散落在代码的很多角落里,而应当被封装到一个对象里面。继承应当被看做是封装变化的方法,而不应当被认为是从一般的对象生成特殊的对象方法。

2.一种可变性不应当与另一种可变性混合在一起。所有的类图的继承结构一般不会超过两层,不然就意味着将两种不同的可变性混合在一起。

 

“开-闭”原则与其他原则的关系:

 

里氏代换原则是,任何基类可以出现的地方,子类一定可以出现。

里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体体现,所以里氏代换原则是对实现抽象化的具体步骤的规范。违反里氏代换原则的,也违背“开-闭”原则,反之不一定成立。

 

依赖倒转原则是,要依赖于抽象,不要依赖于实现。

“开-闭”原则是目标,依赖倒转原则是手段。

 

合成/聚合复用原则是,要尽量使用合成/聚合,而不是继承关系达到复用的目的。

合成/聚合复用原则与里氏代换原则相辅相成,两者都是实现“开-闭”原则的具体步骤的规范。

 

迪米特法则是,一个软件实体应当与尽可能少的其他实体发生相互作用。

一个遵守迪米特原则设计出来的系统在功能需要扩展时,会相对更容易地做到对修改的关闭。

 

接口隔离原则是,应当为客户端提供尽可能小的单独的接口,而不是提供大的总接口。

接口隔离原则与广义的迪米特法则都是对一个软件实体与其他的软件实体的通信的限制。遵循接口隔离原则,会使一个软件系统在功能扩展的过程当中,不会将修改的压力传递到其他的对象。

 

一个重构方法的讨论

 

“将条件转移语句改写成为多态性”是一条广为流传的代码重构做法。

这一做法本身并不能保证“开-闭”原则,应当以“开-闭”原则判断是否需要改写成多态。条件转移并不是错误,如果需要,完全可以选择使用条件转移。

如果一个条件转移语句确实封装了某种商务逻辑的可变性,那么将此种可变性封装起来就符合“开-闭”原则设计思想了。如果一个条件转移语句没有涉及重要的商务逻辑,或者不会随着时间的变化而变化,也不意味着任何的可扩展性,那么它就没有涉及任何有意义的可变性。这时候将这个条件转移语句改写成多态性就是一种没有意义的浪费。

 

抽象类应当拥有尽可能多的共同代码

 在一个继承的等级结构中,共同的代码应当尽量向等级结构的上方移动。把重复的代码从子类里面移动到超类里面,可以提高代码的复用率。在代码发生改变时,设计师之需要修改一个地方。

 

抽象类应当拥有尽可能少的数据

与代码的移动方向相反,数据的移动方向是从抽象类到具体类,向等级结构的下方移动。一个对象的数据不论是否使用都会占用资源,所以应当放到等级结构的低端。

 

什么时候才应当使用继承复用

1.子类是超类的一个特殊种类,而不是超类的一个角色,Is-A才符合继承关系。

2.永远不会出现需要将子类换成另一个类的子类的情况。

3.子类具有扩展超类的责任,而不是具有置换掉(Override)和注销掉(Nullify)超类的责任。

4.只有在分类学角度上有意义时,才可以使用继承,不要从工具类继承。


转载自:“开-闭”原则 (Open-Closed principle, OCP)
posted @ 2011-12-08 16:51 iLinux 阅读(199) | 评论 (0)编辑 收藏

前段时间系统升级时遭遇了OOM,具体解决过程见 遭遇OutOfMemoryError
为了巩固对于java启动各项参数的认识,决定将所有参数列举出来,并一一解释,以便后查;

java启动参数共分为三类;
其一是标准参数(-),所有的JVM实现都必须实现这些参数的功能,而且向后兼容;
其二是非标准参数(-X),默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足,且不保证向后兼容;
其三是非Stable参数(-XX),此类参数各个jvm实现会有所不同,将来可能会随时取消,需要慎重使用;
本文主要描述标准参数部分,剩下的两个部分将会陆续推出;

标准参数列表如下:
-client 
 设置jvm使用client模式,特点是启动速度比较快,但运行时性能和内存管理效率不高,通常用于客户端应用程序或者PC应用开发和调试。

-server
 设置jvm使server模式,特点是启动速度比较慢,但运行时性能和内存管理效率很高,适用于生产环境。在具有64位能力的jdk环境下将默认启用该模式,而忽略-client参数。

-agentlib:libname[=options] 
 用于装载本地lib包;
 其中libname为本地代理库文件名,默认搜索路径为环境变量PATH中的路径,options为传给本地库启动时的参数,多个参数之间用逗号分隔。在Windows平台上jvm搜索本地库名为libname.dll的文件,在linux上jvm搜索本地库名为libname.so的文件,搜索路径环境变量在不同系统上有所不同,比如Solaries上就默认搜索LD_LIBRARY_PATH。
 比如:-agentlib:hprof
 用来获取jvm的运行情况,包括CPU、内存、线程等的运行数据,并可输出到指定文件中;windows中搜索路径为JRE_HOME/bin/hprof.dll。

-agentpath:pathname[=options] 
 按全路径装载本地库,不再搜索PATH中的路径;其他功能和agentlib相同;更多的信息待续,在后续的JVMTI部分会详述。

-classpath classpath 
-cp classpath
 
 告知jvm搜索目录名、jar文档名、zip文档名,之间用分号;分隔;使用-classpath后jvm将不再使用CLASSPATH中的类搜索路径,如果-classpath和CLASSPATH都没有设置,则jvm使用当前路径(.)作为类搜索路径。
 jvm搜索类的方式和顺序为:Bootstrap,Extension,User。
 Bootstrap中的路径是jvm自带的jar或zip文件,jvm首先搜索这些包文件,用System.getProperty("sun.boot.class.path")可得到搜索路径。
 Extension是位于JRE_HOME/lib/ext目录下的jar文件,jvm在搜索完Bootstrap后就搜索该目录下的jar文件,用System.getProperty("java.ext.dirs")可得到搜索路径。
 User搜索顺序为当前路径.、CLASSPATH、-classpath,jvm最后搜索这些目录,用System.getProperty("java.class.path")可得到搜索路径。

-Dproperty=value
 设置系统属性名/值对,运行在此jvm之上的应用程序可用System.getProperty("property")得到value的值。
 如果value中有空格,则需要用双引号将该值括起来,如-Dname="space string"。
 该参数通常用于设置系统级全局变量值,如配置文件路径,以便该属性在程序中任何地方都可访问。

-enableassertions[:<package name>"..." | :<class name> ] 
-ea[:<package name>"..." | :<class name> ]
 
 上述参数就用来设置jvm是否启动断言机制(从JDK 1.4开始支持),缺省时jvm关闭断言机制。
 用-ea 可打开断言机制,不加<packagename>和classname时运行所有包和类中的断言,如果希望只运行某些包或类中的断言,可将包名或类名加到-ea之后。例如要启动包com.wombat.fruitbat中的断言,可用命令java -ea:com.wombat.fruitbat...<Main Class>。

-disableassertions[:<package name>"..." | :<class ; ] 
-da[:<package name>"..." | :<class name> ]

 用来设置jvm关闭断言处理,packagename和classname的使用方法和-ea相同,jvm默认就是关闭状态。
 该参数一般用于相同package内某些class不需要断言的场景,比如com.wombat.fruitbat需要断言,但是com.wombat.fruitbat.Brickbat该类不需要,则可以如下运行:
 java -ea:com.wombat.fruitbat...-da:com.wombat.fruitbat.Brickbat <Main Class>。
 
-enablesystemassertions 
-esa
 
 激活系统类的断言。
 
-disablesystemassertions 
-dsa
 
 关闭系统类的断言。

-jar 
 指定以jar包的形式执行一个应用程序。
 要这样执行一个应用程序,必须让jar包的manifest文件中声明初始加载的Main-class,当然那Main-class必须有public static void main(String[] args)方法。

-javaagent:jarpath[=options] 
 指定jvm启动时装入java语言设备代理。
 Jarpath文件中的mainfest文件必须有Agent-Class属性。代理类也必须实现公共的静态public static void premain(String agentArgs, Instrumentation inst)方法(和main方法类似)。当jvm初始化时,将按代理类的说明顺序调用premain方法;具体参见java.lang.instrument软件包的描述。

-verbose 
-verbose:class
 
 输出jvm载入类的相关信息,当jvm报告说找不到类或者类冲突时可此进行诊断。
-verbose:gc 
 输出每次GC的相关情况。
-verbose:jni 
 输出native方法调用的相关情况,一般用于诊断jni调用错误信息。
 
-version 
 输出java的版本信息,比如jdk版本、vendor、model。
-version:release 
 指定class或者jar运行时需要的jdk版本信息;若指定版本未找到,则以能找到的系统默认jdk版本执行;一般情况下,对于jar文件,可以在manifest文件中指定需要的版本信息,而不是在命令行。
 release中可以指定单个版本,也可以指定一个列表,中间用空格隔开,且支持复杂组合,比如:
 -version:"1.5.0_04 1.5*&1.5.1_02+"
 指定class或者jar需要jdk版本为1.5.0_04或者是1.5系列中比1.5.1_02更高的所有版本。

-showversion 
 输出java版本信息(与-version相同)之后,继续输出java的标准参数列表及其描述。
 
-? 
-help
 
 输出java标准参数列表及其描述。

-X 
 输出非标准的参数列表及其描述。

以上的这些参数我们经常会在很多情况下用到多个的组合,比如我们在用JProfiler进行跟踪监控时,需要在被监控java启动参数中加上如下配置:
-agentlib:jprofilerti=port=8849  -Xbootclasspath/a:/usr/local/jprofiler5/bin/agent.jar
其中就用到两个-agentlib和-X参数,bootclasspath参数的详细信息将会在非标准参数中详细说明。

转自:http://blog.csdn.net/sfdev/article/details/2062042

这篇文章补充说明了-X、-XX参数的说明:Java命令行运行参数说明大全(偷来的)

posted @ 2011-12-08 15:49 iLinux 阅读(5144) | 评论 (0)编辑 收藏

     摘要: 作者:北南南北赞助: eTony,pandonny,懒猫, Arch来自:LinuxSir.Org摘要: 超级用户是系统最高权限的拥有者,是系统管理唯一的胜任者;由于权限的超级并且达到无所不能的地步,如果管理不擅,必会对系统安全造成威胁。 除了尽可能的避免用直接用超级用户root登录系统外,我们还要学会在普通用户下临时切换到超级用户root下完成必要的系统管理工作;从用户管理和...  阅读全文
posted @ 2011-12-08 15:36 iLinux 阅读(1469) | 评论 (0)编辑 收藏

hibernate中,比如B类继承了A类,它们是可以对应同一张表的。
可以参考如下文章Hibernate继承映射一:每个类分层结构一张表

posted @ 2011-12-08 12:50 iLinux 阅读(137) | 评论 (0)编辑 收藏

1 web容器启动,初始化ActionServlet,加载struts-config.xml,根据请求路径和信息找到ActionBean与FormBean

2 确定将要调用的ActionBean与FormBean,将请求中包含的值填充到FormBean中(Action中要准备好ActionMapping的参数)

3 struts将请求分发到相应的的ActionBean处理,ActionMapping参数ActionForm参数request,resposne都做为参数传给处理请求的ActionBean的execute方法

4 Action调用业务逻辑方法,得到返回值ActionForward对象

5 控制控重回ActionServlet,根据Action返回的ActionForward对象,转发到相应的页面

6 处理结果返回浏览器

posted @ 2011-12-08 12:29 iLinux 阅读(111) | 评论 (0)编辑 收藏

UML类图中的关联、聚合、组合

posted @ 2011-12-08 12:25 iLinux 阅读(111) | 评论 (0)编辑 收藏

nio:  http://jiayanjujyj.iteye.com/blog/1044364



posted @ 2011-12-08 00:14 iLinux 阅读(817) | 评论 (0)编辑 收藏

1 小白长得很像他的哥哥,打一句成语

答案:真相大白
Q:老板,你这不叫牛肉面吗?怎么连牛肉都没有?!  

A:人家还叫老婆饼呢,难不成你买的时候还送你一个老婆 ?! 
Q一根手指头的英文叫做 ONE,两根手指头的英文叫做TWO,依次类推,四根手手指头的英文叫做 four,那么弯起来的四根手指头的英文叫什么  

A答案:WONDERFFUL (弯的 FOUR)  
Q:一只兔子和一只跑得很快的乌龟赛跑,猜一猜谁赢拉?  

A:兔子 ~~

Q:错~!是乌龟拉,前面有说是一只跑很快的乌龟,跑很快噢~~

Q:兔子不甘心,又和一只戴了墨镜的乌龟比赛跑步,这次谁赢拉?  

A:恩。。兔子吧

Q:错~~!那只乌龟把墨镜一摘,也!又是刚才那只跑很快的乌龟噢

english version: http://translate.google.com/translate?langpair=zh-CN%7Cen&hl=zh-CN&ie=UTF8&u=http%3A//www.blogjava.net/iLinux/archive/2011/12/07/322634.html
posted @ 2011-12-07 23:31 iLinux 阅读(143) | 评论 (0)编辑 收藏

括号为是否线程安全
list: LinkedList(no) ArrayList(no) Vector(yes) Stack(yes)
map: HashMap(no) LinkedHashMap(no) HashTable(yes) WeakHashMap TreeMap
set: HashSet(no) LinkedHashSet(no) SortedSet TreeSet
最常用的好像为每行的前两个
特征:
1. Linked开头的适合快速插入,删除元素, linked维护元素插入的次序
2. Set 在 HashMap 的基础上实现, 所以Set结尾的key是不会重复的
3. Tree开头的是每次改变发生排序的, 速度慢
适用:
1. 需要快速插入,删除元素, 用 LinkedList; 需要快速随机访问元素,用 ArrayList
2. Vector 类似 ArrayList, 但是是同步的
3. Stack 继承 Vector , 是后进先出的堆栈
4. HashMap, put进去的对象位置会发生变化, LinkedHashMap 则不会
5. HashSet 是专门为快速查询而设计的, 插入会产生排序(LinkedHashSet 不会), 存入HashSet的对象必须定义hashCode方法
   我的补充:关于“存入HashSet的对象必须定义hashCode方法”,其实不是必须的,但是,当我们没有重写hashCode()时,则所有我们添加进Set的对象都不会有重复现象,我们可以添加多个具有相等值得对象,但是,这就与我们的初衷有了背离,Set本身用于存储unique的对象,所以我们重写hashCode()和equals(),符合我们的业务逻辑。
6. SortedSet 是保持元素的有序顺序的Set接口, 添加到 SortedSet 实现类的元素必须实现Comparable接口, TreeSet 类是它的唯一一份实现
其它:
1. 非同步的可以进行外部同步,或者使用Collections.synchronizedMap()的方法包装成一个thread-safe的Map/Set
2. LinkedHashMap支持两种排序:插入顺序、访问顺序。前者是指按照插入时的顺序排序,后者是指按照最旧使用到最近使用的顺序
3. 既然 Set 在 HashMap 的基础上实现, 那么 HashMap 和 HashSet 有什么区别吗?
答: HashMap提供get和put方法, 允许null 值和null 键; HashSet 提供add、remove、contains和size方法, 允许null 元素; 其它未知

转自:http://xu20cn.blog.51cto.com/274020/229009/
posted @ 2011-12-07 17:02 iLinux 阅读(884) | 评论 (0)编辑 收藏

一、事务的4个基本特征 
    当事务处理系统创建事务时,将确保事务有某些特性。组件的开发者们假设事务的特性应该是一些不需要他们亲自管理的特性。这些特性称为ACID特性。 ACID就是:原子性(Atomicity )、一致性( Consistency )、隔离性或独立性( Isolation)和持久性(Durabilily)。 
1、原子性 (Atomicity ) 
    原子性属性用于标识事务是否完全地完成,一个事务的任何更新要在系统上完全完成,如果由于某种原因出错,事务不能完成它的全部任务,系统将返回到事务开始前的状态。 
让我们再看一下银行转帐的例子。如果在转帐的过程中出现错误,整个事务将会回滚。只有当事务中的所有部分都成功执行了,才将事务写入磁盘并使变化 永久化。为了提供回滚或者撤消未提交的变化的能力,许多数据源采用日志机制。例如,SQL Server使用一个预写事务日志,在将数据应用于(或提交到)实际数据页面前,先写在事务日志上。但是,其他一些数据源不是关系型数据库管理系统 (RDBMS),它们管理未提交事务的方式完全不同。只要事务回滚时,数据源可以撤消所有未提交的改变,那么这种技术应该可用于管理事务。 
2、一致性( Consistency ) 
    事务在系统完整性中实施一致性,这通过保证系统的任何事务最后都处于有效状态来实现。如果事务成功地完成,那么系统中所有变化将正确地应用,系统处于有效状态。如果在事务中出现错误,那么系统中的所有变化将自动地回滚,系统返回到原始状态。因为事务开 
始时系统处于一致状态,所以现在系统仍然处于一致状态。 再让我们回头看一下银行转帐的例子,在帐户转换和资金转移前,帐户处于有效状态。如果事务成功地完成,并且提交事务,则帐户处于新的有效的状态。如果事务出错,终止后,帐户返回到原先的有效状态。 
记住,事务不负责实施数据完整性,而仅仅负责在事务提交或终止以后确保数据返回到一致状态。理解数据完整性规则并写代码实现完整性的重任通常落在 开发者肩上,他们根据业务要求进行设计。 当许多用户同时使用和修改同样的数据时,事务必须保持其数据的完整性和一致性。因此我们进一步研究A C I D特性中的下一个特性:隔离性。 
3、隔离性 ( Isolation) 
    在隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在 系统中认为只有该事务在使用系统。 这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据。重要的是,在隔离状态执行事务, 系统的状态有可能是不一致的,在结束事务前,应确保系统处于一致状态。但是在每个单独的事务中,系统的状态可能会发生变化。如果事务不是在隔离状态运行, 它就可能从系统中访问数据,而系统可能处于不一致状态。通过提供事务隔离,可以阻止这类事件的发生。在银行的示例中,这意味着在这个系统内,其他过程和事 务在我们的事务完成前看不到我们的事务引起的任何变化,这对于终止的情况非常重要。如果有另一个过程根据帐户余额进行相应处理,而它在我们的事务完成前就 能看到它造成的变化,那么这个过程的决策可能 
建立在错误的数据之上,因为我们的事务可能终止。这就是说明了为什么事务产生的变化,直到事务完成,才对系统的其他部分可见。隔离性不仅仅保 证多个事务不能同时修改相同数据,而且能够保证事务操作产生的变化直到变化被提交或终止时才能对另一个事务可见,并发的事务彼此之间毫无影响。这就意味着 所有要求修改或读取的数据已经被锁定在事务中,直到事务完成才能释放。大多数数据库,例如SQL Server以及其他的RDBMS,通过使用锁定来实现隔离,事务中涉及的各个数据项或数据集使用锁定来防止并发访问。 
4、持久性 (Durabilily) 
    持久性意味着一旦事务执行成功,在系统中产生的所有变化将是永久的。应该存在一些检查点防止在系统失败时丢失信息。甚至硬件本身失败,系统的状态仍能通过在日志中记录事务完成的任务进行重建。持久性的概念允许开发者认为不管系统以后发生了什么变化,完 
成的事务是系统永久的部分。 在银行的例子中,资金的转移是永久的,一直保持在系统中。这听起来似乎简单,但这,依赖于将数据写入磁盘,特别需要指出的是,在事务完全完成并提交后才写 入磁盘的。 所有这些事务特性,不管其内部如何关联,仅仅是保证从事务开始到事务完成,不管事务成功与否,都能正确地管理事务涉及的数据 ,当事务处理系统创建事务 时,将确保事务有某些特性。组件的开发者们假设事务的特性应该是一些不需要他们亲自管理的特性。 
二、为什么需要对事务并发控制 
    如果不对事务进行并发控制,我们看看数据库并发操作是会有那些异常情形 
1、丢失更新(Lost update) 
    两个事务都同时更新一行数据,但是第二个事务却中途失败退出,导致对数据的两个修改都失效了。 
2、脏读(Dirty Reads) 
    一个事务开始读取了某行数据,但是另外一个事务已经更新了此数据但没有能够及时提交。这是相当危险的,因为很可能所有的操作都被回滚。 
3、非重复读(Non-repeatable Reads) 
   一个事务对同一行数据重复读取两次,但是却得到了不同的结果。同一查询在同一事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时发生非重复读。 
4、二类丢失更新(Second lost updates problem) 
    无法重复读取的特例。有两个并发事务同时读取同一行数据,然后其中一个对它进行修改提交,而另一个也进行了修改提交。这就会造成第一次写操作失效。 
5、幻像读(Phantom Reads) 
    事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查 
询中未出现的数据(这里并不要求两次查询的SQL语句相同)。这是因为在两次查询过程中有另外一个事务插入数据造成的。 
三、数据库的隔离级别 
   为了兼顾并发效率和异常控制,在标准SQL规范中,定义了4个事务隔离级别,(ORACLE和SQLSERER对标准隔离级别有不同的实现 ) 
1、未提交读(Read Uncommitted) 
    直译就是"读未提交",意思就是即使一个更新语句没有提交,但是别 
的事务可以读到这个改变.这是很不安全的。允许任务读取数据库中未提交的数据更改,也称为脏读。 
2、提交读(Read Committed) 
   直译就是"读提交",可防止脏读,意思就是语句提交以后即执行了COMMIT以后 
别的事务就能读到这个改变. 只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 
3、可重复读(Repeatable Read): 
   直译就是"可以重复读",这是说在同一个事务里面先后执行同一个查询语句的时候,得到的结果是一样的.在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读 
4、串行读(Serializable) 
   直译就是"序列化",意思是说这个事务执行的时候不允许别的事务并发执行. 完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞

 

四,隔离级别对并发的控制 
下表是各隔离级别对各种异常的控制能力。


LU丢失更新DR脏读NRR非重复读SLU二类丢失更新PR幻像读
未提交读 RUYYYYY
提交读 RCNNYYY
可重复读 RRNNNNY
串行读 SNNNNN

 

 

顺便举一小例。

MS_SQL: 
--事务一 
set transaction isolation level serializable 
begin tran 
insert into test values('xxx') 
--事务二 
set transaction isolation level read committed 
begin tran 
select * from test 
--事务三 
set transaction isolation level read uncommitted 
begin tran 
select * from test 
在查询分析器中执行事务一后,分别执行事务二,和三。结果是事务二会等待,而事务三则会执行。

ORACLE: 
--事务一 
set transaction isolation level serializable; 
insert into test values('xxx'); 
select * from test; 
--事务二 
set transaction isolation level read committed--ORACLE默认级别 
select * from test 
执行事务一后,执行事务二。结果是事务二只读出原有的数据,无视事务一的插入操作。

MYSQL 
查看InnoDB系统级别的事务隔离级别: 
以下为引用的内容: 
mysql> SELECT @@global.tx_isolation; 
+-----------------------+ 
| @@global.tx_isolation | 
+-----------------------+ 
| REPEATABLE-READ   | 
+-----------------------+ 
1 row in set (0.00 sec) 
查看InnoDB会话级别的事务隔离级别: 
以下为引用的内容: 
mysql> SELECT @@tx_isolation; 
+-----------------+ 
| @@tx_isolation | 
+-----------------+ 
| REPEATABLE-READ | 
+-----------------+ 
1 row in set (0.00 sec) 
修改事务隔离级别: 
以下为引用的内容: 
  mysql> set global transaction isolation level read committed; 
  Query OK, 0 rows affected (0.00 sec) 
  mysql> set session transaction isolation level read committed; 
  Query OK, 0 rows affected (0.00 sec) 
InnoDB的可重复读隔离级别和其他数据库的可重复读是有区别的,不会造成幻象读(phantom read),所谓幻象读,就是同一个事务内,多次select,可以读取到其他session insert并已经commit的数据。下面是一个小的测试,证明InnoDB的可重复读隔离级别不会造成幻象读。测试涉及两个session,分别为 session 1和session 2,隔离级别都是repeateable read,关闭autocommit 
以下为引用的内容: 
mysql> select @@tx_isolation; 
+-----------------+ 
| @@tx_isolation | 
+-----------------+ 
| REPEATABLE-READ | 
+-----------------+ 
1 row in set (0.00 sec) 
  mysql> set autocommit=off; 
  Query OK, 0 rows affected (0.00 sec) 
  session 1 创建表并插入测试数据 
  mysql> create table test(i int) engine=innodb; 
  Query OK, 0 rows affected (0.00 sec)

  mysql> insert into test values(1); 
  Query OK, 1 row affected (0.00 sec) 
  session 2 查询,没有数据,正常,session1没有提交,不允许脏读 
  mysql> select * from test; 
  Empty set (0.00 sec) 
  session 1 提交事务 
  mysql> commit; 
  Query OK, 0 rows affected (0.00 sec) 
  session 2 查询,还是没有数据,没有产生幻象读 
  mysql> select * from test; 
  Empty set (0.00 sec) 
以上试验版本: 
mysql> select version(); 
+-------------------------+ 
| version()       | 
+-------------------------+ 
| 5.0.37-community-nt-log | 
+-------------------------+ 
1 row in set (0.00 sec)

五、并发一致性问题的解决办法 
1 封锁(Locking) 
    封锁是实现并发控制的一个非常重要的技术。所谓封锁就是事务T在对某个数据对象例如表、记录等操作之前,先向系统发出请求,对其加锁。加锁后事务T就对该 数据对象有了一定的控制,在事务T释放它的锁之前,其它的事务不能更新此数据对象。 基本的封锁类型有两种:排它锁(Exclusive locks 简记为X锁)和共享锁(Share locks 简记为S锁)。 
    排它锁又称为写锁。若事务T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。这就保证了其它事务在T释放A上的锁之前不能再读取和修改A。 
    共享锁又称为读锁。若事务T对数据对象A加上S锁,则其它事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这就保证了其它事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。 
2 封锁协议 
    在 运用X锁和S锁这两种基本封锁,对数据对象加锁时,还需要约定一些规则,例如应何时申请X锁或S锁、持锁时间、何时释放等。我们称这些规则为封锁协议 (Locking Protocol)。对封锁方式规定不同的规则,就形成了各种不同的封锁协议。下面介绍三级封锁协议。三级封锁协议分别在不同程度上解决了丢失的修改、不 可重复读和读"脏"数据等不一致性问题,为并发操作的正确调度提供一定的保证。下面只给出三级封锁协议的定义,不再做过多探讨。 
    1 级封锁协议是:事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放。事务结束包括正常结束(COMMIT)和非正常结束(ROLLBACK)。 1级封锁协议可防止丢失修改,并保证事务T是可恢复的。在1级封锁协议中,如果仅仅是读数据不对其进行修改,是不需要加锁的,所以它不能保证可重复读和不 读"脏"数据。 
    2级封锁协议是:1级封锁协议加上事务T在读取数据R之前必须先对其加S锁,读完后即可释放S锁。2级封锁协议除防止了丢失修改,还可进一步防止读"脏"数据。 
    3级封锁协议是:1级封锁协议加上事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放。3级封锁协议除防止了丢失修改和不读'脏'数据外,还进一步防止了不可重复读。 
六、一般处理并发问题时的步骤: 
1、开启事务。 
2、申请写权限,也就是给对象(表或记录)加锁。 
3、假如失败,则结束事务,过一会重试。 
4、假如成功,也就是给对象加锁成功,防止其他用户再用同样的方式打开。 
5、进行编辑操作。 
6、写入所进行的编辑结果。 
7、假如写入成功,则提交事务,完成操作。 
8、假如写入失败,则回滚事务,取消提交。 
9、(7.8)两步操作已释放了锁定的对象,恢复到操作前的状态。

转自:http://www.cnblogs.com/tqsummer/archive/2010/07/11/1775209.html

posted @ 2011-12-07 14:11 iLinux 阅读(559) | 评论 (0)编辑 收藏

具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的,但实际上它还有其他选择。

    cookie机制。正统的cookie分发是通过扩展HTTP协议来实现的,服务器通过在HTTP的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的cookie。然而纯粹的客户端脚本如JavaScript或者VBScript也可以生成cookie。而cookie的使用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器检查所有存储的cookie,如果某个cookie所声明的作用范围大于等于将要请求的资源所在的位置,则把该cookie附在请求资源的HTTP请求头上发送给服务器
    cookie的内容主要包括:名字,值,过期时间,路径和域。路径与域一起构成cookie的作用范围若不设置过期时间,则表示这个cookie的生命期为浏览器会话期间,关闭浏览器窗口,cookie就消失。这种生命期为浏览器会话期的cookie被称为会话cookie。会话cookie一般不存储在硬盘上而是保存在内存里,当然这种行为并不是规范规定的。若设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie仍然有效直到超过设定的过期时间。存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存里的cookie,不同的浏览器有不同的处理方式
    session机制。session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
 
    当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否已包含了一个session标识(称为session id),如果已包含则说明以前已经为此客户端创建过session,服务器就按照session id把这个session检索出来使用(检索不到,会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个session id将被在本次响应中返回给客户端保存。
    保存这个session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于SEEESIONID。但cookie可以被人为的禁止,则必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。
    经常被使用的一种技术叫做URL重写,就是把session id直接附加在URL路径的后面。还有一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。比如:
     <form name="testform" action="/xxx">
     <input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">
     <input type="text">
     </form>
实际上这种技术可以简单的用对action应用URL重写来代替。
posted @ 2010-06-02 15:03 iLinux 阅读(149) | 评论 (0)编辑 收藏

第一部分 DWR是什么,如何使用

    DWR是一个开源的类库,可以帮助开发人员开发包含AJAX技术的网站.它可以允许在浏览器里的代码(javascript)使用运行在WEB服务器上的 JAVA函数,就像它就在浏览器里一样. 它包含两个主要的部分:允许JavaScript从WEB服务器上一个遵循了AJAX原则的Servlet(小应用程序)中获取数据.另外一方面一个 JavaScript库可以帮助网站开发人员轻松地利用获取的数据来动态改变网页的内容.
    官方网站地址http://getahead.org/dwr

关于DWR的使用 引用别人的文章。   

开始使用 DWR
    原文出处: http://www.javatang.com/archives/2006/10/20/254879.html
    翻译: Jet Mah
    有两种方法来开始 DWR 的学习,最简单的做法是下载官方提供的 WAR 文件然后对此深入研究。不过这种方式不能使你感到将 DWR 整合到你现有的 web 程序有多么的简单,所以我们推荐你跟随下面三个步骤:

1. 安装 DWR JAR 包
下载 dwr.jar 文件,然后将它放在 web 程序的 WEB-INF/lib 目录下面,很可能在这个目录下已经有一些 jar 文件了。

2. 编辑 config 文件

将下面的代码添加到 WEB-INF/web.xml 文件中,<servlet>需要放在另外的<servlet>之后,<servlet-mapping>也是如此。

<servlet>
   <servlet-name>dwr-invoker</servlet-name>
   <display-name>DWR Servlet</display-name>
   <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
   <init-param>
      <param-name>debug</param-name>
      <param-value>true</param-value>
   </init-param>
</servlet>

<servlet-mapping>
   <servlet-name>dwr-invoker</servlet-name>
   <url-pattern>/dwr/*</url-pattern>
</servlet-mapping>

接下来创建 dwr.xml 文件并将此放在 web.xml 所在的 WEB-INF 目录下。文件中类似下面的内容:

<!DOCTYPE dwr PUBLIC
     ”-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN”
     ”http://www.getahead.ltd.uk/dwr/dwr10.dtd”>

<dwr>
   <allow>
     <create creator=”new” javascript=”JDate”>
       <param name=”class” value=”java.util.Date”/>
     </create>
     <create creator=”new” javascript=”Demo”>
       <param name=”class” value=”your.java.Bean”/>
     </create>
   </allow>
</dwr>

DWR 配置文件定义了由 DWR 创建和被 Javascript 远程使用的类。在上面的例子中我们在远程创建了2个类,并且给出了在 Javascript 中的类名。

上面使用的 new creator 使用了所有的 JavaBeans 必须含有的公有(public)无参(no-args)的构造函数。值得一提的是, DWR 还有一些限制:

  • 避免使用 JavaScript 保留字;以保留字命名的方法将自动被排除。大多数 JavaScript 的保留字同时也是 Java 的保留字,因此无论如何你也不能使用一个名为 “try()” 的方法。但是最常用的一个词 “delete()”,在 JavaScript 中有特殊的含义而在 Java 中没有。
  • 重载方法(Overloaded methods)将会在调用的时候陷入未知的状况,因此应该避免重载方法。

    3. 访问下面的地址
    http://localhost:8080/[YOUR-WEBAPP]/dwr/

    你应该会看到一个页面,上面显示了刚才你在第二步所创建的类。进入一个链接之后你会看到所有等待调用方法的列表。这些动态产生的例子你也能通过 DWR 来实现。

    亲自尝试和体会下吧。

    怎样应用到你的 Web 程序中?

    在侧边栏有很多例子演示了怎样改变网页中的文本、更新列表、操作表单和动态修改表格。每一个例子都有详细的说明。

    另外一个开始方法就是从页面中查看源代码,这些页面你刚刚浏览过:

  • 进入 http://localhost:8080/[YOUR-WEBAPP]/dwr/ 然后点击你创建的类;
  • 查看源代码然后定位到你所感兴趣的方法的代码行;
  • 将这些文本粘贴到你 Web 程序的一个 HTML 或 JSP页面中;
  • 包含下面的 javascrip 文件:

    <script src=’/[YOUR-WEBAPP]/dwr/interface/[YOUR-SCRIPT].js’></script>
    <script src=’/[YOUR-WEBAPP]/dwr/engine.js’></script>

    你可以根据实际情况修改 /[YOUR-WEBAPP]/ 部分。

    关于怎样书写 DWR 控制的 Javascript 代码请查看 脚本简介

  • posted @ 2010-06-02 14:40 iLinux 阅读(140) | 评论 (0)编辑 收藏

         摘要:   阅读全文
    posted @ 2010-03-29 16:13 iLinux 阅读(4838) | 评论 (0)编辑 收藏

    是不是应该进入有可能实施互联网、广电系统、电信领域的某一方呢?
    机遇的声音喊得很响亮,金三银四的日子,想动一动了

    posted @ 2010-03-15 14:13 iLinux 阅读(75) | 评论 (0)编辑 收藏

    简单讨论JVM的class加载机制,给出两个反射的例子代码并分析工作原理,并给出了sun的动态代理实现原理——代码生成

    JavaVM,反射与动态代理

     

    Java程序的工作机制:Java对象都以单独的class文件存在,java虚拟机将其载入并执行其虚拟机指令。

     

    Java虚拟机查找这些java对象:

    java虚拟机根据class path来查找java对象,而虚拟机的class path又分为三层:

    bootstrapsun.boot.class.path

    extension: java.ext.dirs

    application: java.class.path

    三个class path各有对应的classloader。由上而下形成父子关系

    当程序中调用new指令,或者ClassLoader.load方法时。其顺序如下:

    1.       首先查看applicationclassloader中是否已有对应的class缓存,如果有则返回,并根据class分配内存。如果没有,接下一步。

    2.       首先查看extensionclassloader中是否已有对应的class缓存,如果有则返回,并根据class分配内存。如果没有,接下一步。

    3.       首先查看bootstrapclassloader中是否已有对应的class缓存,如果有则返回,并根据class分配内存。如果没有,接下一步。

    4.       bootstrapclassloader在其class path中试图加载该class,如果有,则将该class放入cache中,并返回。如果没有,接下一步。

    5.       extensionclassloader在其class path中试图加载该class,如果有,则将该class放入cache中,并返回。如果没有,接下一步。

    6.       applicationclassloader在其class path中试图加载该class,如果有,则将该class放入cache中,并返回。如果没有,则抛出ClassNotFoundexception

     

    Java虚拟机加载这些java对象:

    每个java虚拟机都在其启动时产生一个唯一的class heap,并把所有的class instance都分配在其中。其中每个类实例的信息又分两部分,fields域和methods域。每个类实例各自拥有fields,但同一个类的不同实例共享methods

     

    反射

    JVM对反射的处理

    简单例子代码:

    import java.lang.reflect.InvocationHandler;

    import java.lang.reflect.Method;

    import java.lang.reflect.InvocationTargetException;

    import java.io.IOException;

     

    public class Main {

        public static void main(String[] args){

            TempImpl t1 = new TempImpl("temp1");

            try {

                Method t1Talk = t1.getClass().getMethod("Talk", new Class[0]) ;

                t1Talk.invoke(t1, null);

            } catch (NoSuchMethodException e) {

                e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

            } catch (IllegalAccessException e) {

                e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

            } catch (InvocationTargetException e) {

                e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

            }

            try {

                System.in.read();

            } catch (IOException e) {

                e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

            }

        }

    }

    复杂例子代码:

    import java.lang.reflect.InvocationHandler;

    import java.lang.reflect.Method;

    import java.lang.reflect.InvocationTargetException;

    import java.io.IOException;

     

    public class Main {

        public static void main(String[] args){

            TempImpl t1 = new TempImpl("temp1");

            TempImpl t2 = new TempImpl("temp2");

            Temp2 temp2 = new Temp2();

            try {

                Method t1Talk = t1.getClass().getMethod("Talk", new Class[0]) ;

                Method t2Talk = t2.getClass().getMethod("Talk", new Class[0]) ;

                t1Talk.invoke(t2, null);

                t2Talk.invoke(t1, null);

                if(t1Talk.equals(t2Talk)){

                    System.out.println("equals");

                }

               else{

                    System.out.println("not equals");

                }

                if(t1Talk==t2Talk){

                    System.out.println("ref equals");

                }

               else{

                    System.out.println("ref not equals");

                }

                t2Talk.invoke(temp2, null);

            } catch (NoSuchMethodException e) {

                e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

            } catch (IllegalAccessException e) {

                e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

            } catch (InvocationTargetException e) {

                e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

            }

            try {

                System.in.read();

            } catch (IOException e) {

                e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

            }

        }

    }

     

    分析:java虚拟机把每个methods当作一个执行单元。该执行单元带有两种签名:类签名和属性签名(publicstatic等)。 反射的第一步,验证签名的合法性。验证通过后,顺序执行该method中的指令,当需要访问类实例的fields和传入参数时,由虚拟机注入。

     

    动态代理

    Sun对动态代理的说明:

    一个简单例子代码:

    动态代理的内部实现——代码生成:

    研究JDK源代码,发现在Proxysun实现中调用了sun.misc.ProxyGenerator类的generateProxyClass( proxyName, interfaces)方法,其返回值为byte[]class文件的内存类型一致。于是做如下试验:

    public class ProxyClassFile{

           public static void main(String[] args){

                  String proxyName = "TempProxy";

            TempImpl t = new TempImpl("proxy");

                  Class[] interfaces =t.getClass().getInterfaces();

                 

                  byte[] proxyClassFile = ProxyGenerator.generateProxyClass(

                      proxyName, interfaces);

            File f = new File("classes/TempProxy.class");

            try {

                FileOutputStream fos = new FileOutputStream(f);

                fos.write(proxyClassFile);

                fos.flush();

                fos.close();

            } catch (FileNotFoundException e) {

                e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

            } catch (IOException e) {

                e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

            }

           }

    }

    运行该类,到class文件夹下,利用反编译技术,发现原来其采用了代码生产技术:

     

    public interface Temp{

           public void Talk();

           public void Run();

    }

    import java.lang.reflect.*;

     

    public final class TempProxy extends Proxy

        implements Temp{

     

        private static Method m4;

        private static Method m2;

        private static Method m0;

        private static Method m3;

        private static Method m1;

     

        public TempProxy(InvocationHandler invocationhandler)   {

            super(invocationhandler);

        }

     

        public final void Run()    {

            try {

                h.invoke(this, m4, null);

                return;

            }

            catch(Error _ex) { }

            catch(Throwable throwable) {

                throw new UndeclaredThrowableException(throwable);

            }

        }

     

        public final String toString(){

            try{

                return (String)h.invoke(this, m2, null);

            }

            catch(Error _ex) { }

            catch(Throwable throwable)  {

                throw new UndeclaredThrowableException(throwable);

            }

            return "";

        }

     

        public final int hashCode() {

            try {

                return ((Integer)h.invoke(this, m0, null)).intValue();

            }

            catch(Error _ex) { }

            catch(Throwable throwable){

                throw new UndeclaredThrowableException(throwable);

            }

            return 123;

        }

     

        public final void Talk(){

            try{

                h.invoke(this, m3, null);

                return;

            }

            catch(Error _ex) { }

            catch(Throwable throwable) {

                throw new UndeclaredThrowableException(throwable);

            }

        }

     

        public final boolean equals(Object obj) {

            try {

                return ((Boolean)h.invoke(this, m1, new Object[] {

                    obj

                })).booleanValue();

            }

            catch(Error _ex) { }

            catch(Throwable throwable) {

                throw new UndeclaredThrowableException(throwable);

            }

            return false;

        }

     

        static{

            try{

         m4 = Class.forName("Temp").getMethod("Run", new Class[0]);

         m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);

         m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);

         m3 = Class.forName("Temp").getMethod("Talk", new Class[0]);

         m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {

                    Class.forName("java.lang.Object")

                });

            }

            catch(NoSuchMethodException nosuchmethodexception) {

               throw new NoSuchMethodError(nosuchmethodexception.getMessage());

            }

            catch(ClassNotFoundException classnotfoundexception) {

                throw new NoClassDefFoundError(classnotfoundexception.getMessage());

            }

        }

    }

     from: http://www.cnblogs.com/fengye/archive/2007/02/18/652389.html

    posted @ 2010-02-10 14:00 iLinux 阅读(163) | 评论 (0)编辑 收藏