用xdoclet生成hibernate映射文件

首先你要下载xdoclet-1.2.3,ant1.6.5,然后写项目管理文件build.properties,build.xml。 举例如下: build.properties内容: xdoclet.lib=E:/xdoclet-1.2.3/lib build.xml内容: <?xml version="1.0" encoding="UTF-8"?> <project name="pms" default="" basedir="."> <property file="build.properties" /> <property name="app.home" value="." /> <property name="app.name" value="pms" /> <property name="src.dir" value="${app.home}/src" /> <path id="xdoclet.classpath"> <fileset dir="${xdoclet.lib}"> <include name="*.jar" /> </fileset> </path> <!-- =================================================================== --> <!-- Initialise --> <!-- =================================================================== --> <target name="init"> <tstamp> <format property="TODAY" pattern="d-MM-yy" /> </tstamp> <taskdef name="hibernatedoclet" classname="xdoclet.modules.hibernate.HibernateDocletTask" classpathref="xdoclet.classpath" /> </target> <!-- =================================================================== --> <!-- The "hibernatedoclet" target generates Hibernate mapping files --> <!-- based on XDoclet marked-up Plain Old Java Object (POJO) --> <!-- =================================================================== --> <target name="hibernatedoclet" depends="init" unless="hibernatedoclet.unnecessary" description="Generate Hibernate mapping files"> <taskdef name="hibernatedoclet" classname="xdoclet.modules.hibernate.HibernateDocletTask" classpathref="compile.classpath" /> <!-- generate hibernate files --> <hibernatedoclet destdir="${src.dir}" mergedir="${src.dir}" excludedtags="@version,@author,@todo,@see" addedtags="@xdoclet-generated at ${TODAY}" force="false" verbose="false"> <fileset dir="${src.dir}"> <include name="net/pms/model/*.java" /> </fileset> <hibernate version="3.0" /> </hibernatedoclet> </target> </project> javabean如下: package net.pms.model; import java.io.Serializable; import java.util.Date; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.EqualsBuilder; /** * * @author jfish * @hibernate.class table="person" */ public class Person implements Serializable { private static final long serialVersionUID = 1044237873392048222L; private Long id; private String name; private Date createTime; /** * @return Returns the createTime. * @hibernate.property column = "ts" */ public Date getCreateTime() { return createTime; } /** * @param createTime * The createTime to set. */ public void setCreateTime(Date createTime) { this.createTime = createTime; } /** * @return Returns the id. * @hibernate.id column = "person_id" generator-class = "native" * unsaved-value = "not null" */ public Long getId() { return id; } /** * @param id * The id to set. */ public void setId(Long id) { this.id = id; } /** * @return Returns the name. * @hibernate.property */ public String getName() { return name; } /** * @param name * The name to set. */ public void setName(String name) { this.name = name; } /** * @see java.lang.Object#toString() */ public String toString() { return new ToStringBuilder(this).append("name", this.name).append("id", this.id).append("createTime", this.createTime).toString(); } /** * @see java.lang.Object#hashCode() */ public int hashCode() { return new HashCodeBuilder(-96436153, 713792057).appendSuper( super.hashCode()).append(this.createTime).append(this.name) .append(this.id).toHashCode(); } /** * @see java.lang.Object#equals(Object) */ public boolean equals(Object object) { if (!(object instanceof Person)) { return false; } Person rhs = (Person) object; return new EqualsBuilder().appendSuper(super.equals(object)).append( this.createTime, rhs.createTime).append(this.name, rhs.name) .append(this.id, rhs.id).isEquals(); } } 生成的映射文件如下: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="net.pms.model.Person" table="person"> <id name="id" column="person_id" type="java.lang.Long" unsaved-value="not null"> <generator class="native"> <!-- To add non XDoclet generator parameters, create a file named hibernate-generator-params-Person.xml containing the additional parameters and place it in your merge dir. --> </generator> </id> <property name="createTime" type="java.util.Date" update="true" insert="true" column="ts" /> <property name="name" type="java.lang.String" update="true" insert="true" column="name" /> <!-- To add non XDoclet property mappings, create a file named hibernate-properties-Person.xml containing the additional properties and place it in your merge dir. --> </class> </hibernate-mapping> <淘宝热门商品:
 

 

专做VIVI昕薇瑞丽韩日女装~

 

118.00 元 

韩国正品intercrew LED表 真皮皮带款

来源:程序员网

小小豆叮

创建可视化Java Bean—Fabric 1.2 发布

Platespiller 近日宣布Fabric 1.2 正式发布。 Fabric 是一个用于用户界面开发的有力工具,面向创建可视化Java Bean的用户。Fabric 的执行技术Park可以轻松的集合XML-based 用户界面语言到rich 界面。更新内容包括a native launcher for Windows,对JavaScript,L&F,drag-and-drop 的改进,对嵌套组件的支持,以及Park JFC 动作。 下载地址:http://www.platespiller.com/download.jsp <淘宝热门商品:
 

215.00 元  

08秋冬新款 D&G 优质面料修

 

96.00 元 

奥地利进口 专柜礼盒 天然水晶 施家经典STARS

来源:程序员网

小小豆叮

解析Java的Class文件格式——解析魔数和版本号

熟悉Java语言有好几年了,技术也学了一些,现在主要从事J2ME技术方面的工作,最近工作不是很忙,就找了本电子书——《深入Java虚拟机(第二版)》,仔细阅读了一下,读起来比较吃力,现在把Java class文件格式的读书笔记共享给大家。 众所周知,Java语言的可执行文件是class文件,俗称类文件。这个文件为了让不同平台的虚拟机都能够正确的解释,详细规定了其文件格式。下面就按照顺序进行介绍: 1、 魔数(magic) 为了方便虚拟机识别文件是否是class格式的文件,SUN公司规定每个class文件都必须以一个word(4个字节)来开始,这个数字就称为魔数。魔数是有4个字节的无符号数字构成的,而且规定魔数必须是0xCAFEBABE。 2、 版本号(version) 魔数后续的内容就是一个word的长度来表示生成的class文件的版本号,版本号分为主版本号和次版本号,其中前两个字节表示次版本号,后两个字节表示主版本号,排列的顺序遵从高位在前,低位在后的原则。 下面我写了一个很简单的示例代码,从一个名字为First.class文件中读取到这些信息,然后输出出来,不足之处请大家指正! 该程序的代码如下: import java.io.*; /** * 解析class文件格式 */ public class ParseClassFile{ public static void main(String args[]){ try{ //读取文件数据,文件是当前目录下的First.class FileInputStream fis = new FileInputStream("./First.class"); int length = fis.available(); //文件数据 byte[] data = new byte[length]; //读取文件到字节数组 fis.read(data); //关闭文件 fis.close(); //解析文件数据 parseFile(data); }catch(Exception e){ System.out.println(e); } } private static void parseFile(byte[] data){ //输出魔数 System.out.print("魔数(magic):0x"); System.out.print(Integer.toHexString(data[0]).substring(6).toUpperCase()); System.out.print(Integer.toHexString(data[1]).substring(6).toUpperCase()); System.out.print(Integer.toHexString(data[2]).substring(6).toUpperCase()); System.out.println(Integer.toHexString(data[3]).substring(6).toUpperCase()); //主版本号和次版本号码 int minor_version = (((int)data[4]) << 8) + data[5]; int major_version = (((int)data[6]) << 8) + data[7]; System.out.println("版本号(version):" + major_version + "." + minor_version); } } <淘宝热门商品:
 

68.00元  

海洋新奇特购物天堂

 

1.50元  

星钻喜铺◣皇冠信誉◢{100%满意婚庆一站式店铺}特色婚庆用品大全

来源:程序员网

小小豆叮

如何使用JBookMaker制作Java电子书

 在支持JAVA的手机越来越多了,可以说是手机里的一个标准配置功能了,java除了平时打打游戏以外,想必大家用的最多的就是看java电子书了。但是现在网上提供的现成的电子书毕竟还是比较少的,所以大家就想自己动手做属于自己的java书籍,这不,最近就有许多网友问博士怎么制作java电子书,所以今天就来讲一讲这个问题,首先,我们要先下载java电子书制作软件--JbookMaker(文件下载请见文尾处),然后在PC端安装上它,打开软件后显示如下图所示的版权声明: 选择“同意”后出现如下界面: 下面介绍Java书的制作步骤: 1. 选择源文件所在位置,注意,这里你要选择的源文件必须是.TXT文件;   2. 选择输出文件存放目录;   3. 填写文件名(输出的java文件名),书名(Java书安装后显示的名称)和作者;其它选项不必选择;   4. 选择中文排序,保证文章顺序正确;   5. 选择全选;保证所有文章全被选中;   6. 点击制作。   完成后出现下图所示界面,提示制作完成。 <淘宝热门商品:
 

67.00 

【漂亮宝贝】童装打底裤名牌男童裤子背心T恤公主裙

X2-82103青蛙皇子童装130-155CM女中童T恤背心短裤两件套238

 

132.00 元 

假一罚十 专柜正品 进口牛皮单肩包

来源:程序员网

小小豆叮

Java搜索引擎Compass Framework 0.8.0 新版发布

Compass Framework 项目组近日宣布,Compass Framework 0.8.0 新版正式发布。 Compass 具备一个强大的、事务的、高性能的对象/搜索引擎映射,与一个Java持久层框架。 报道中指出,该新版本中主推的新功能是存储Lucene index 在一个数据库中。这主要包括两部分:一是完整的Lucene Jdbc Directory,与任何Compass 相关代码区分开,只采用纯粹的Lucene实现。一是Jdbc Directory集成Compass Framework,允许运行存在的Compass 代码,其中包括几个Data Source Providers(Dbcp,c3p0,Jndi 等等)。 下载地址:http://www.compassframework.org/display/SITE/0.8.0 <淘宝热门商品:
 

¥:7.00 

极限特攻-新奇产品仓库    金秋时节好礼送不停 

创意小猪/手摇式LED手电/手动手电/LED手电

 

¥:59.90 

天使之城外贸服装商行(童装/女装)【双皇冠网店 实体店同步】

双皇冠!韩国安卡米文静米色提花高领毛衣,专柜236元,140码

来源:程序员网

小小豆叮

在Java SE中使用Hibernate框架

目前人们很容易发现Hibernate正迅速的成为流行的J2EE的O/R映射工具和数据集成框架(如果不是最流行的)。Hibernate为企业应用开发者操作关系数据库的提供了清晰明了而又强大的工具。然而如果你需要在外部访问那些包装在J2EE web应用里的实体,情况又怎样呢?你的开发跟应用独立分开,却又相同的实体以访问你的数据吗?又或者你得编写附加的web组件来管理对数据的内部访问吗?   在很多情况下,这些问题都会出现。我的情况是我的公司需要将来自多个供应商,有着多种文件格式的记录导入到数据库里。我想起我以前经常使用的方法,那就是编写Shell和SQL教本(甚至是存储过程)来导入数据。但是由于我们的数据模型太过复杂,我决定在web应用之外尽可能的利用现有的实体,Spring DAO以及服务并且开发一个自定义的J2SE命令行数据加载工具。   大问题:你该怎样呢?   现在很多Hibernate的文档和范例都是绑定在容器上。不管是web应用还是内部的大型应用,总会使用到容器的。人们有很好的理由去使用它。容器是设计来提供对各种特性的支持,例如事务处理,线程以及安全。现今,这些特性都是开发中等规模和企业应用所必需的工具。然而当你需要在容器之外访问实体时,你该怎样呢?你是使用现有的架构和代码呢,还是会从一个不同的角度来解决问题,比如说完全采用另一种开发语言?当然,我们没有正确答案。在本文的余下部分,我将说明我的方法:就是在Spring容器之外重用现有的实体/POJO。   起初,脚本语言,例如Perl,Python,Ruby甚至Tcl(是的,我以前也做过这个)看起来有很多优势。它们能省下很多时间,可以轻易得到初始结果,还能规避许多Hibernate潜在的复杂度。人们完全可能只用几行代码就可以连接数据库,查询结果,已经打印输出到终端屏幕或者日志文件。然而,取决于你的数据模型,事情也(总是)会变得相当复杂。譬如说你有一个表 person, 其中有一个外键属于表 address。当我们添加数据的时候,表address没有正确的插入数据,就会导致表person 也不能插入了。这是个很典型的事务处理方面的问题。也许有人会说在脚本语言中这个问题不难解决,就像在你的主程序里一样。可是问题仍然存在,为什么要这样做呢?业务逻辑不是已经在你的应用里面了吗?为什么要在写一遍代码呢?而且这并不是唯一的情况,你必须重复你的工作和业务逻辑,这样就会带来出错的可能。   然而,有些人会觉得这样也行,他们使用自己觉得最适合的工具。也许你已经因为程序之外的原因而有了某种独立的架构;也许你会在独立的数据库里加载和测试数据,然后在通过各种测试后再迁移到产品的数据库里;又也许你把数据库维护外包出去,你只需要把相关文件发给合作伙伴让他们去处理那些问题。总之,总会有很多理由不使用现有的Hibernate数据层。没有谁对谁错,只是如果你可以也愿意在你的应用之外使用现有的代码,请往下看。我会告诉你一些方法,这能解决你不少的烦恼噢。   配置   如果你觉得可以在容器之外使用现有的Hibernate对象的话,那你首先要做的事就是得自己手工管理所有的配置项,在本文余下部分我所采用的方法是使用一个基于命令行的JAVA程序。既然你已经配置了Hibernate XML配置文件,你应该知道需要提供的参数,例如JNDI DataSource名,实体映射文件,还有其他一些处理SQL日志的属性。如果你想使用命令行程序的话,你就得解决如何解析XML文件和把它添加到配置项中的这些问题。虽然解析XML文件也不难,但这本身并不是我们的重点。因此,我建议使用propetries文件,properties文件比较直观而且容易加载并从中读取数据。下面是配置Hibernate所需要的最小属性集(不包括任何实体映射)。   清单1: hibernate.dialect=net.sf.hibernate.dialect.PostgreSQLDialect hibernate.connection.driver_class=org.postgresql.Driver hibernate.connection.url=jdbc:postgresql://devserver/devdb hibernate.connection.username=dbuserhibernate.connection.password=dbpassword hibernate.query.substitutions yes Y   正如你所看到的,上面的属性值指定了数据库方言,JDBC驱动,数据库url,用户名,用户密码,以及是否使用查找替换。只要定义以上几项数值并保存在文件hibernate.properties里(要放置在你的类路径里面哦),就能很轻松的加载,填充到Hibernate Configuation类里面。   清单2: Properties props = new Properties(); try {  props.load(props.getClass().getResourceAsStream("hibernate.properties")); }catch(Exception e){  System.out.println("Error loading hibernate properties.");  e.printStackTrace();  System.exit(0); } String driver = props.getProperty("hibernate.connection.driver_class"); String connUrl = props.getProperty("hibernate.connection.url"); String username = props.getProperty("hibernate.connection.username"); String password = props.getProperty("hibernate.connection.password"); // In my examples, I use Postgres, but Hibernate // supports virtually every popular dbms out there.Class.forName("org.postgresql.Driver"); Connection conn = DriverManager.getConnection(connUrl, username, password); Configuration cfg = new Configuration(); cfg.setProperties( props ); SessionFactory sessions = cfg.buildSessionFactory(); Session session = sessions.openSession(conn);   这样我们就得到了Hibernate Session类了。但我们也有必要解决如何利用现有的实体映射这个问题。在《Hibernate in Action》一书中,提到怎样从实体映射XML文件中加载,如下所示:   清单3: Configuration cfg = new Configuration(); cfg.addResource("hello/Message.hbm.xml"); cfg.setProperties( System.getProperties() ); SessionFactory sessions = cfg.buildSessionFactory();   这段代码清晰的说明了从hello包里加载Message实体定义的过程。对于这个例子来说还好,但对那些有多个实体的应用来说,就很单一而且容易出错。不仅映射关系是硬编码,还得手工管理每次添加一个新的实体就要更新实体加载的代码。其实有跟简单的方法去查找和加载映射关系以使其与最新的jar文件保持一致。   首先,在你的web服务器或者企业服务器里,映射文件需要放置在类路径里,这样Hibernate才能正常的运行。这样做是很有好处的,因为你所需要做的就是使用同样的jar包和查找相应的映射文件的名字。因为你可能会有多个jar文件在你的类路径里,你需要指定哪个jar包包含了映射文件。以下就是一种查找映射关系的方法   清单4: String cp = System.getProperty("java.class.path"); String jarFile = null; List hbmList = null;String[] cparr = cp.split("\\:"); for(int j=0;j
 

268.00 元 

绝对NO1新版mirifem魔力丰丰胸片

 

26.00 元  

时尚巴黎女人街 V 火爆这个冬季

附带女人我最大推荐魔法烘罩器电吹风机人性化冷暖风切换魔发冬夏

来源:程序员网

小小豆叮

浅析Java语言中两种异常使用的差别

Java提供了两类主要的异常:runtime exception和checked exception。所有的checked exception是从java.lang.Exception类衍生出来的,而runtime exception则是从java.lang.RuntimeException或java.lang.Error类衍生出来的。 它们的不同之处表现在两方面:机制上和逻辑上。 一、机制上 它们在机制上的不同表现在两点:1.如何定义方法;2. 如何处理抛出的异常。请看下面CheckedException的定义: public class CheckedException extends Exception {  public CheckedException() {}  public CheckedException( String message )  {   super( message );  } } 以及一个使用exception的例子: public class ExceptionalClass {  public void method1()   throws CheckedException   {    // ... throw new CheckedException( "...出错了" );   }  public void method2( String arg )   {    if( arg == null )    {     throw new NullPointerException( "method2的参数arg是null!" );    }   }  public void method3() throws CheckedException   {    method1();   } } 你可能已经注意到了,两个方法method1()和method2()都会抛出exception,可是只有method1()做了声明。另外,method3()本身并不会抛出exception,可是它却声明会抛出CheckedException。在向你解释之前,让我们先来看看这个类的main()方法: public static void main( String[] args ) {  ExceptionalClass example = new ExceptionalClass();  try  {   example.method1();   example.method3();  }  catch( CheckedException ex ) { } example.method2( null ); } 在main()方法中,如果要调用method1(),你必须把这个调用放在try/catch程序块当中,因为它会抛出Checked exception。 相比之下,当你调用method2()时,则不需要把它放在try/catch程序块当中,因为它会抛出的exception不是checked exception,而是runtime exception。会抛出runtime exception的方法在定义时不必声明它会抛出exception。 现在,让我们再来看看method3()。它调用了method1()却没有把这个调用放在try/catch程序块当中。它是通过声明它会抛出method1()会抛出的exception来避免这样做的。它没有捕获这个exception,而是把它传递下去。实际上main()方法也可以这样做,通过声明它会抛出Checked exception来避免使用try/catch程序块(当然我们反对这种做法)。 小结一下: * Runtime exceptions: 在定义方法时不需要声明会抛出runtime exception; 在调用这个方法时不需要捕获这个runtime exception; runtime exception是从java.lang.RuntimeException或java.lang.Error类衍生出来的。 * Checked exceptions: 定义方法时必须声明所有可能会抛出的checked exception; 在调用这个方法时,必须捕获它的checked exception,不然就得把它的exception传递下去; checked exception是从java.lang.Exception类衍生出来的 <淘宝热门商品:
 

27.50 元  

兼济天下 公司运营 多家实体店 毛巾 浴巾 美容巾 浴袍 毛巾被

【皇冠信誉 专业做毛巾】外贸原单★素色绣小圆点浴巾◎加厚

 

 

衣品堂

来源:程序员网

小小豆叮

Java函数编程工具FunctionalJ 发布

FunctionalJ 是一个开源的工具包,能够帮助你在Java中进行函数编程。 Java 语言中常被忽视的一个方面是它被归类为一种命令式(imperative)编程语言。命令式编程虽然由于与 Java 语言的关联而相当普及,但是并不是惟一可用的编程风格,也不总是最有效的。如果您从事大型企业项目开发,您就会熟悉编写模块化代码的好处。良构的、模块化的代码更容易编写、调试、理解和重用。虽然函数编程范型长期以来只是通过像 Haskell、Scheme、Erlang 和 Lisp 这样的特殊语言实现。但是在Java中,你也一样可以进行函数编程。 下载地址:http://functionalj.sourceforge.net/ <淘宝热门商品:
 

52.00 元  

【卡盟在线】

皇冠在线充|QQ黑钻腾讯黑钻地下城与勇士(DNF)黑钻3月

 

198.00 元 

08秋款欧洲正版G-star双排扣夹克外套 超好

来源:程序员网

小小豆叮

专访Java之父:Java是否能够与时俱进

CNET科技资讯网1月9日国际报道 点燃一场网络战争争论之火的保险的方法是说一种程序语言比另外一种好。作为“Java之父”的James Gosling 比任何人都清楚这一点。   在他最近的网络日志中,Gosling 卷入了Java和脚本语言的争论。   和Java相比,PHP 和Python等脚本语言更容易学习,它们在开发人员当中相当的流行 ,尤其是那些网页开发者。很多人,包括一些前Java语言的拥护者都认为,脚本语言和所谓的LAMP开源部件正在蓬勃发展,而这种发展减弱了Java的影响。   最近,Gosling 接受了CNET新闻网站的采访,内容包括关于程序语言永远休止的争论,争论的好处以及Java的未来方向。   问:目前,人们对Java的优点正在进行讨论。很多人认为,脚本语言正在替代Java语言。那么,Java的用户正在减少吗?它过时了吗?它正在老而不合时宜了吗?   Gosling :我倒是希望这种情况是真的,那可以让我的生活轻松些。但是,我看到的资料,比如Evans Data的调查显示,很多人仍然在使用Java及其相关的技术,没有迹象显示它正在走下坡路。   我知道,很多人希望它走下坡路。对于我而言,最激动的事情莫过于存在多样性的途径。   为什么你希望Java过时了?   Gosling :我已经从事这方面的工作很长时间了,有时候我就想,如果能休个假就好了。   Evans Data的调查显示,尽管在亚洲地区的用户数在上升,过去两年半,北美地区的Java用户数却在下降。   PHP 和脚本语言正变得越来越流行、如果你看看Web2.0公司的情况,你就会发现他们中的很多正在使用AJAX这种包含了脚本语言的开发工具。   Gosling :AJAX只是用JavaScript来开发先进玩意儿的模式。它确实很酷,但它肯定也有它的问题。   是的。有一本名为“超越Java”的书讲,Java对一些事情来讲很棒,但对Web 开发,另外一些开发语言和架构要更适合些。你对此的观点是什么?你认为这种观点有根据吗?   Gosling :当你看看php 这样专注于Web 开发的语言,如果你只是想去做网页,你就会发现它们确实很好。   它几乎是JSP 的一种克隆。   我认为,当你准备超越单纯的网页开发的范畴,事情就变得有些混乱。当你想作一些分析或整合的工作,PHP 就变得比较的困难了,因为它主要专注于网页开发。   我们经常发现,很多人用PHP 来做网页,而涉及到底层的数据分析时,他们就用Java代码来完成。通常的情况并不是一种技术替代另外一种技术,而是一种技术补充另外一种技术。   是不是说,Java主要使用在服务器端,而脚本语言主要应用于前台,对于Java来讲,这难道不是一个问题吗?   Gosling :我自己认为,在计算任务的世界里,Web 前台这些事情总是要更加的直接和简单些。在Java的范畴内,人们也做了很多的脚本方面的东西,象JavaScript,Groovy,J/Python和J/Ruby.   有一点经常被人遗忘,这就是,Java是一种两种层面上的语言:它既是一种虚拟机,它也是一种ASCII 语言。   很多人看不到虚拟机的神奇之处,但有很多很多的脚本语言已经建立在这种虚拟机之上了。   为何你希望有脚本语言和Java虚拟机相联系呢?   Gosling :使用脚本语言的好处是,它们可以快速的访问巨大的工具库,它们的性能和协同性也相当的好。   你可以使用Groovy,然后访问零售点的终端,智能卡,数据库等等。   Java语言的设计初衷是那些分布式的计算,它一般被用于复杂的任务。Java是否应该被用于简单任务?   Gosling :从历史来讲,它在处理简单任务方面表现很出色。   过去几年,Java的一个设计方向是在高端。如果你在一家银行,你希望驾驭一台晚间处理1 千亿美元的服务器,那么Java可以很多的胜任这一点。   易用性曾经是Java发展的一个障碍。你们是怎么克服这一点的?   Gosling :事实上,我们并不是去改变语言,这是因为,如果你想让一种语言变得简单,你往往会破坏它处理高端任务的能力。我们已经做了一些简化的工作,比如Java Studio Creator ,你可以用它来拖拉AJAX部件,处理数据库访问等等任务。用它来做网页相当的快。   过去几年,LAMP(linux+apache+MySQL+PHP)逐渐兴起,你认为它是ava 世界以外的一种成熟的选择吗?   Gosling :LAMP当然已经变得相当的成熟,Java和LAMP配合得相当的完美。   总体上讲,我希望这块市场存在多样性的选择。   听起来,你好象不太担心 Ruby on Rails,PHP 或者LAMP这些开发模式的崛起。这些东西不属于Java的范畴,但你似乎觉得它们相当的好。   Gosling :事实上,我认为它们相当的酷。所有这些东西事实上都协同工作。比如J/Ruby,它就是在Java虚拟机上部署的Ruby. 这相当的漂亮。我认为,那些脚本语言的开发人员其实还不够与众不同。   什么意思?   Gosling :如果你看看它们的程序,你就会发现,它们看起来就像Java程序一样。   Java是将继续保持一种通用语言和平台风格呢,还是专门向移动或者服务器之类的专业方向发展?   Gosling :这里存在很多的矛盾。一方面,你从专门化哪里获得了很多的动力。另外一方面,你的这种动力又来自通用性。   开发世界的人希望出现流行趋势,那么,你希望Java成为流行吗?   Gosling :八九年前,Java就已经是流行趋势了。它真的是一种有趣的事情,因为Java已经不是一个单独的东西了,它已经成为很多不同东西的集合。 <淘宝热门商品:
 

35.00 元  

〓朩玲〓网游点卡专卖店『无分店无小号!无手机充值卡!』

【五钻自动发货】跑跑卡丁车40元400点专用卡【充值看商品说明】

 

 

伊人红妆赛维芦荟胶相宜本草昭贵田缘舞沙千纤草大宝庆琇郁美净

来源:程序员网

小小豆叮

体验Java 5.0的新增语言特性

Java 5.0发布了,许多人都将开始使用这个JDK版本的一些新增特性。从增强的for循环到诸如泛型(generic)之类更复杂的特性,都将很快出现在您所编写的代码中。我们刚刚完成了一个基于Java 5.0的大型任务,而本文就是要介绍我们使用这些新特性的体验。本文不是一篇入门性的文章,而是对这些特性以及它们所产生的影响的深入介绍,同时还给出了一些在项目中更有效地使用这些特性的技巧。   简介   在JDK 1.5的beta阶段,我们为BEA的Java IDE开发了一个Java 5编译器。因为我们实现了许多新特性,所以人们开始以新的方式利用它们;有些用法很聪明,而有些用法明显应该被列入禁用清单。编译器本身使用了新的语言特性,所以我们也获得了使用这些特性维护代码的直接体验。本文将介绍其中的许多特性和使用它们的体验。   我们假定您已经熟悉了这些新特性,所以不再全面介绍每个特性,而是谈论一些有趣的、但很可能不太明显的内容和用法。这些技巧出自我们的实际体验,并大致按照语言特性进行了分类。   我们将从最简单的特性开始,逐步过渡到高级特性。泛型所包含的内容特别丰富,因此占了本文一半的篇幅。   增强的for循环   为了迭代集合和数组,增强的for循环提供了一个简单、兼容的语法。有两点值得一提:   Init表达式   在循环中,初始化表达式只计算一次。这意味着您通常可以移除一个变量声明。在这个例子中,我们必须创建一个整型数组来保存computeNumbers()的结果,以防止每一次循环都重新计算该方法。您可以看到,下面的代码要比上面的代码整洁一些,并且没有泄露变量numbers:   未增强的For:   int sum = 0;   Integer[] numbers = computeNumbers();   for (int i=0; i < numbers.length ; i++) sum += numbers[i];    增强后的For:    int sum = 0;   for ( int number: computeNumbers() ) sum += number;  局限性   有时需要在迭代期间访问迭代器或下标,看起来增强的for循环应该允许该操作,但事实上不是这样,请看下面的例子: for (int i=0; i < numbers.length ; i++) { if (i != 0) System.out.print(","); System.out.print(numbers[i]); }  我们希望将数组中的值打印为一个用逗号分隔的清单。我们需要知道目前是否是第一项,以便确定是否应该打印逗号。使用增强的for循环是无法获知这种信息的。我们需要自己保留一个下标或一个布尔值来指示是否经过了第一项。   这是另一个例子: for (Iterator it = n.iterator() ; it.hasNext() ; ) if (it.next() < 0) it.remove();  在此例中,我们想从整数集合中删除负数项。为此,需要对迭代器调用一个方法,但是当使用增强的for 循环时,迭代器对我们来说是看不到的。因此,我们只能使用Java 5之前版本的迭代方法。   顺便说一下,这里需要注意的是,由于Iterator是泛型,所以其声明是Iterator。许多人都忘记了这一点而使用了Iterator的原始格式。   注释   注释处理是一个很大的话题。因为本文只关注核心的语言特性,所以我们不打算涵盖它所有的可能形式和陷阱。  我们将讨论内置的注释(SuppressWarnings,Deprecated和Override)以及一般注释处理的局限性。   Suppress Warnings   该注释关闭了类或方法级别的编译器警告。有时候您比编译器更清楚地知道,代码必须使用一个被否决的方法或执行一些无法静态确定是否类型安全的动作,而使用: @SuppressWarnings("deprecation") public static void selfDestruct() { Thread.currentThread().stop(); }  这可能是内置注释最有用的地方。遗憾的是,1.5.0_04的javac不支持它。但是1.6支持它,并且Sun正在努力将其向后移植到1.5中。 Eclipse 3.1中支持该注释,其他IDE也可能支持它。这允许您把代码彻底地从警告中解脱出来。如果在编译时出现警告,可以确定是您刚刚把它添加进来——以帮助查看那些可能不安全的代码。随着泛型的添加,它使用起来将更趁手。   Deprecated   遗憾的是,Deprecated没那么有用。它本来旨在替换@deprecated javadoc标签,但是由于它不包含任何字段,所以也就没有方法来建议deprecated类或方法的用户应该使用什么做为替代品。大多数用法都同时需要javadoc标签和这个注释。 Override   Override表示,它所注释的方法应该重写超类中具有相同签名的方法: @Override public int hashCode() { ... }  看上面的例子,如果没有在hashCode中将“C”大写,在编译时不会出现错误,但是在运行时将无法像期望的那样调用该方法。通过添加Override标签,编译器会提示它是否真正地执行了重写。   在超类发生改变的情况中,这也很有帮助。如果向该方法中添加一个新参数,而且方法本身也被重命名了,那么子类将突然不能编译,因为它不再重写超类的任何东西。   其它注释   注释在其他场景中非常有用。当不是直接修改行为而是增强行为时,特别是在添加样板代码的情况下,注释在诸如EJB和Web services这样的框架中运行得非常好。 注释不能用做预处理器。Sun的设计特别预防了完全因为注释而修改类的字节码。这样可以正确地理解该语言的成果,而且IDE之类的工具也可以执行深入的代码分析和重构之类的功能。   注释不是银弹。第一次遇到的时候,人们试图尝试各种技巧。请看下面这个从别人那里获得的建议: public class Foo { @Property private int bar; }  其思想是为私有字段bar自动创建getter和setter方法。遗憾的是,这个想法有两个失败之处:1)它不能运行,2)它使代码难以阅读和处理。   它是无法实现的,因为前面已经提到了,Sun特别阻止了对出现注释的类进行修改。   即使是可能的,它也不是一个好主意,因为它使代码可读性差。第一次看到这段代码的人会不知道该注释创建了方法。此外,如果将来您需要在这些方法内部执行一些操作,注释也是没用的。   总之,不要试图用注释去做那些常规代码可以完成的事情。   枚举   enum非常像public static final int声明,后者作为枚举值已经使用了很多年。对int所做的最大也是最明显的改进是类型安全——您不能错误地用枚举的一种类型代替另一种类型,这一点和int不同,所有的int对编译器来说都是一样的。除去极少数例外的情况,通常都应该用enum实例替换全部的枚举风格的int结构。   枚举提供了一些附加的特性。EnumMap和EnumSet这两个实用类是专门为枚举优化的标准集合实现。如果知道集合只包含枚举类型,那么应该使用这些专门的集合来代替Has                                   hMap或HashSet。   大部分情况下,可以使用enum对代码中的所有public static final int做插入替换。它们是可比的,并且可以静态导入,所以对它们的引用看起来是等同的,即使是对于内部类(或内部枚举类型)。注意,比较枚举类型的时候,声明它们的指令表明了它们的顺序值。   “隐藏的”静态方法   两个静态方法出现在所有枚举类型声明中。因为它们是枚举子类上的静态方法,而不是Enum本身的方法,所以它们在java.lang.Enum的javadoc中没有出现。   第一个是values(),返回一个枚举类型所有可能值的数组。   第二个是valueOf(),为提供的字符串返回一个枚举类型,该枚举类型必须精确地匹配源代码声明。   方法   关于枚举类型,我们最喜欢的一个方面是它可以有方法。过去您可能需要编写一些代码,对public static final int进行转换,把它从数据库类型转换为JDBC URL。而现在则可以让枚举类型本身带一个整理代码的方法。下面就是一个例子,包括DatabaseType枚举类型的抽象方法以及每个枚举实例中提供的实现: public enum DatabaseType { ORACLE { public String getJdbcUrl() {...} }, MYSQL { public String getJdbcUrl() {...} }; public abstract String getJdbcUrl(); }  现在枚举类型可以直接提供它的实用方法。例如: DatabaseType dbType = ...; String jdbcURL = dbType.getJdbcUrl();   要获取URL,必须预先知道该实用方法在哪里。   可变参数(Vararg)   正确地使用可变参数确实可以清理一些垃圾代码。典型的例子是一个带有可变的String参数个数的log方法: Log.log(String code) Log.log(String code, String arg) Log.log(String code, String arg1, String arg2) Log.log(String code, String[] args)   当讨论可变参数时,比较有趣的是,如果用新的可变参数替换前四个例子,将是兼容的: Log.log(String code, String... args)   所有的可变参数都是源兼容的——那就是说,如果重新编译log()方法的所有调用程序,可以直接替换全部的四个方法。然而,如果需要向后的二进制兼容性,那么就需要舍去前三个方法。只有最后那个带一个字符串数组参数的方法等效于可变参数版本,因此可以被可变参数版本替换。   类型强制转换   如果希望调用程序了解应该使用哪种类型的参数,那么应该避免用可变参数进行类型强制转换。看下面这个例子,第一项希望是String,第二项希望是Exception: Log.log(Object... objects) { String message = (String)objects[0]; if (objects.length > 1) { Exception e = (Exception)objects[1]; // Do something with the exception } }  方法签名应该如下所示,相应的可变参数分别使用String和Exception声明: Log.log(String message, Exception e, Object... objects) {...}   不要使用可变参数破坏类型系统。需要强类型化时才可以使用它。对于这个规则,PrintStream.printf()是一个有趣的例外:它提供类型信息作为自己的第一个参数,以便稍后可以接受那些类型。   协变返回   协变返回的基本用法是用于在已知一个实现的返回类型比API更具体的时候避免进行类型强制转换。在下面这个例子中,有一个返回Animal对象的Zoo接口。我们的实现返回一个AnimalImpl对象,但是在JDK 1.5之前,要返回一个Animal对象就必须声明。: public interface Zoo { public Animal getAnimal(); } public class ZooImpl implements Zoo { public Animal getAnimal(){ return new AnimalImpl(); } }  协变返回的使用替换了三个反模式: 直接字段访问。为了规避API限制,一些实现把子类直接暴露为字段: ZooImpl._animal 另一种形式是,在知道实现的实际上是特定的子类的情况下,在调用程序中执行向下转换: ((AnimalImpl)ZooImpl.getAnimal()).implMethod(); 我看到的最后一种形式是一个具体的方法,该方法用来避免由一个完全不同的签名所引发的问题: ZooImpl._getAnimal();   这三种模式都有它们的问题和局限性。要么是不够整洁,要么就是暴露了不必要的实现细节。   协变   协变返回模式就比较整洁、安全并且易于维护,它也不需要类型强制转换或特定的方法或字段: public AnimalImpl getAnimal(){ return new AnimalImpl(); }   使用结果: ZooImpl.getAnimal().implMethod();   使用泛型   我们将从两个角度来了解泛型:使用泛型和构造泛型。我们不讨论List、Set和Map的显而易见的用法。知道泛型集合是强大的并且应该经常使用就足够了。   我们将讨论泛型方法的使用以及编译器推断类型的方法。通常这些都不会出问题,但是当出问题时,错误信息会非常令人费解,所以需要了解如何修复这些问题。 泛型方法   除了泛型类型,Java 5还引入了泛型方法。在这个来自java.util.Collections的例子中,构造了一个单元素列表。新的List的元素类型是根据传入方法的对象的类型来推断的: static List Collections.singletonList(T o)   示例用法: public List getListOfOne() { return Collections.singletonList(1); }  在示例用法中,我们传入了一个int。所以方法的返回类型就是List。编译器把T推断为Integer。这和泛型类型是不同的,因为您通常不需要显式地指定类型参数。 这也显示了自动装箱和泛型的相互作用。类型参数必须是引用类型:这就是为什么我们得到的是List而不是List。   不带参数的泛型方法   emptyList()方法与泛型一起引入,作为java.util.Collections中EMPTY_LIST字段的类型安全置换: static List Collections.emptyList()   示例用法: public List getNoIntegers() { return Collections.emptyList(); }  与先前的例子不同,这个方法没有参数,那么编译器如何推断T的类型呢?基本上,它将尝试使用一次参数。如果没有起作用,它再次尝试使用返回或赋值类型。在本例中,返回的是List,所以T被推断为Integer。   如果在返回语句或赋值语句之外的位置调用泛型方法会怎么样呢?那么编译器将无法执行类型推断的第二次传送。在下面这个例子中,emptyList()是从条件运算符内部调用的: public List getNoIntegers() { return x ? Collections.emptyList() : null; }  因为编译器看不到返回上下文,也不能推断T,所以它放弃并采用Object。您将看到一个错误消息,比如:“无法将List转换为List。” 为了修复这个错误,应显式地向方法调用传递类型参数。这样,编译器就不会试图推断类型参数,就可以获得正确的结果: return x ? Collections.emptyList() : null;  这种情况经常发生的另一个地方是在方法调用中。如果一个方法带一个List参数,并且需要为那个参数调用这个传递的emptyList(),那么也需要使用这个语法。   集合之外   这里有三个泛型类型的例子,它们不是集合,而是以一种新颖的方式使用泛型。这三个例子都来自标准的Java库: Class Class在类的类型上被参数化了。这就使无需类型强制转换而构造一个newInstance成为可能。 Comparable Comparable被实际的比较类型参数化。这就在compareTo()调用时提供了更强的类型化。例如,String实现Comparable。对除String之外的任何东西调用compareTo(),都会在编译时失败。 Enum> Enum被枚举类型参数化。一个名为Color的枚举类型将扩展Enum。getDeclaringClass()方法返回枚举类型的类对象,在这个例子中就是一个Color对象。它与getClass()不同,后者可能返回一个无名类。   通配符   泛型最复杂的部分是对通配符的理解。我们将讨论三种类型的通配符以及它们的用途。   首先让我们了解一下数组是如何工作的。可以从一个Integer[]为一个Number[]赋值。如果尝试把一个Float写到Number[]中,那么可以编译,但在运行时会失败,出现一个ArrayStoreException: Integer[] ia = new Integer[5]; Number[] na = ia; na[0] = 0.5; // compiles, but fails at runtime   如果试图把该例直接转换成泛型,那么会在编译时失败,因为赋值是不被允许的: List iList = new ArrayList(); List nList = iList; // not allowed nList.add(0.5);  如果使用泛型,只要代码在编译时没有出现警告,就不会遇到运行时ClassCastException。   上限通配符   我们想要的是一个确切元素类型未知的列表,这一点与数组是不同的。   List是一个列表,其元素类型是具体类型Number。   List是一个确切元素类型未知的列表。它是Number或其子类型。   上限   如果我们更新初始的例子,并赋值给List,那么现在赋值就会成功了: List iList = new ArrayList(); List nList = iList; Number n = nList.get(0); nList.add(0.5); // Not allowed  我们可以从列表中得到Number,因为无论列表的确切元素类型是什么(Float、Integer或Number),我们都可以把它赋值给Number。   我们仍然不能把浮点类型插入列表中。这会在编译时失败,因为我们不能证明这是安全的。如果我们想要向列表中添加浮点类型,它将破坏iList的初始类型安全——它只存储Integer。   通配符给了我们比数组更多的表达能力。   为什么使用通配符   在下面这个例子中,通配符用于向API的用户隐藏类型信息。在内部,Set被存储为CustomerImpl。而API的用户只知道他们正在获取一个Set,从中可以读取Customer。 此处通配符是必需的,因为无法从Set向Set赋值: public class CustomerFactory { private Set _customers; public Set getCustomers() { return _customers; } }  通配符和协变返回   通配符的另一种常见用法是和协变返回一起使用。与赋值相同的规则可以应用到协变返回上。如果希望在重写的方法中返回一个更具体的泛型类型,声明的方法必须使用通配符: public interface NumberGenerator { public List generate(); } public class FibonacciGenerator extends NumberGenerator { public List generate() { ... } }  如果要使用数组,接口可以返回Number[],而实现可以返回Integer[]。   下限   我们所谈的主要是关于上限通配符的。还有一个下限通配符。List是一个确切“元素类型”未知的列表,但是可能是Mnumber,或者Number的超类型。所以它可能是一个List或一个List。   下限通配符远没有上限通配符那样常见,但是当需要它们的时候,它们就是必需的。   下限与上限 List readList = new ArrayList(); Number n = readList.get(0); List writeList = new ArrayList(); writeList.add(new Integer(5));  第一个是可以从中读数的列表。   第二个是可以向其写数的列表。   无界通配符   最后,List列表的内容可以是任何类型,而且它与List几乎相同。可以随时读取Object,但是不能向列表中写入内容。 公共API中的通配符   总之,正如前面所说,通配符在向调用程序隐藏实现细节方面是非常重要的,但即使下限通配符看起来是提供只读访问,由于remove(int position)之类的非泛型方法,它们也并非如此。如果您想要一个真正不变的集合,可以使用java.util.Collection上的方法,比如unmodifiableList()。   编写API的时候要记得通配符。通常,在传递泛型类型时,应该尝试使用通配符。它使更多的调用程序可以访问API。   通过接收List而不是List,下面的方法可以由许多不同类型的列表调用: void removeNegatives(List list);  构造泛型类型   现在我们将讨论构造自己的泛型类型。我们将展示一些例子,其中通过使用泛型可以提高类型安全性,我们还将讨论一些实现泛型类型时的常见问题。   集合风格(Collection-like)的函数   第一个泛型类的例子是一个集合风格的例子。Pair有两个类型参数,而且字段是类型的实例: public final class Pair { public final A first; public final B second; public Pair(A first, B second) { this.first = first; this.second = second; } }  这使从方法返回两个项而无需为每个两种类型的组合编写专用的类成为可能。另一种方法是返回Object[],而这样是类型不安全或者不整洁的。   在下面的用法中,我们从方法返回一个File和一个Boolean。方法的客户端可以直接使用字段而无需类型强制转换: public Pair getFileAndWriteStatus(String path){ // create file and status return new Pair(file, status); } Pair result = getFileAndWriteStatus("..."); File f = result.first; boolean writeable = result.second;  集合之外   在下面这个例子中,泛型被用于附加的编译时安全性。通过把DBFactory类参数化为所创建的Peer类型,您实际上是在强制Factory子类返回一个Peer的特定子类型: public abstract class DBFactory { protected abstract T createEmptyPeer(); public List get(String constraint) { List peers = new ArrayList(); // database magic return peers; } }   通过实现DBFactory,CustomerFactory必须从createEmptyPeer()返回一个Customer: public class CustomerFactory extends DBFactory{ public Customer createEmptyPeer() { return new Customer(); } }  泛型方法   不管想要对参数之间还是参数与返回类型之间的泛型类型施加约束,都可以使用泛型方法:   例如,如果编写的反转函数是在位置上反转,那么可能不需要泛型方法。然而,如果希望反转返回一个新的List,那么可能会希望新List的元素类型与传入的List的类型相同。在这种情况下,就需要一个泛型方法: List reverse(List list)   具体化   当实现一个泛型类时,您可能想要构造一个数组T[]。因为泛型是通过擦除(erasure)实现的,所以这是不允许的。   您可以尝试把Object[]强制转换为T[]。但这是不安全的。   具体化解决方案   按照泛型教程的惯例,解决方案使用的是“类型令牌”,通过向构造函数添加一个Class参数,可以强制客户端为类的类型参数提供正确的类对象: public class ArrayExample { private Class clazz; public ArrayExample(Class clazz) { this.clazz = clazz; } public T[] getArray(int size) { return (T[])Array.newInstance(clazz, size); } }  为了构造ArrayExample,客户端必须把String.class传递给构造函数,因为String.class的类型是Class。   拥有类对象使构造一个具有正确元素类型的数组成为可能。 <淘宝热门商品:
 

36.9元  

◢◤80工厂◥◣-亚洲最大最全(B2C)创意家居礼品购物网

 

28.00 元  

保健食品,散装,正装由你选

来源:程序员网

小小豆叮

MD5的Java Bean实现

MD5简介 MD5的全称是Message-Digest Algorithm 5,在90年代初由MIT的计算机科学实验室和RSA Data Security Inc发明,经MD2、MD3和MD4发展而来。 Message-Digest泛指字节串(Message)的Hash变换,就是把一个任意长度的字节串变换成一定长的大整数。请注意我使用了“字节串”而不是“字符串”这个词,是因为这种变换只与字节的值有关,与字符集或编码方式无关。 MD5将任意长度的“字节串”变换成一个128bit的大整数,并且它是一个不可逆的字符串变换算法,换句话说就是,即使你看到源程序和算法描述,也无法将一个MD5的值变换回原始的字符串,从数学原理上说,是因为原始的字符串有无穷多个,这有点象不存在反函数的数学函数。 MD5的典型应用是对一段Message(字节串)产生fingerprint(指纹),以防止被“篡改”。举个例子,你将一段话写在一个叫readme.txt文件中,并对这个readme.txt产生一个MD5的值并记录在案,然后你可以传播这个文件给别人,别人如果修改了文件中的任何内容,你对这个文件重新计算MD5时就会发现。如果再有一个第三方的认证机构,用MD5还可以防止文件作者的“抵赖”,这就是所谓的数字签名应用。 MD5还广泛用于加密和解密技术上,在很多操作系统中,用户的密码是以MD5值(或类似的其它算法)的方式保存的,用户Login的时候,系统是把用户输入的密码计算成MD5值,然后再去和系统中保存的MD5值进行比较,而系统并不“知道”用户的密码是什么。 一些黑客破获这种密码的方法是一种被称为“跑字典”的方法。有两种方法得到字典,一种是日常搜集的用做密码的字符串表,另一种是用排列组合方法生成的,先用MD5程序计算出这些字典项的MD5值,然后再用目标的MD5值在这个字典中检索。 即使假设密码的最大长度为8,同时密码只能是字母和数字,共26+26+10=62个字符,排列组合出的字典的项数则是P(62,1)+P(62,2)….+P(62,8),那也已经是一个很天文的数字了,存储这个字典就需要TB级的磁盘组,而且这种方法还有一个前提,就是能获得目标账户的密码MD5值的情况下才可以。 在很多电子商务和社区应用中,管理用户的Account是一种最常用的基本功能,尽管很多Application Server提供了这些基本组件,但很多应用开发者为了管理的更大的灵活性还是喜欢采用关系数据库来管理用户,懒惰的做法是用户的密码往往使用明文或简单的变换后直接保存在数据库中,因此这些用户的密码对软件开发者或系统管理员来说可以说毫无保密可言,本文的目的是介绍MD5的Java Bean的实现,同时给出用MD5来处理用户的Account密码的例子,这种方法使得管理员和程序设计者都无法看到用户的密码,尽管他们可以初始化它们。但重要的一点是对于用户密码设置习惯的保护。 有兴趣的读者可以从这里取得MD5也就是RFC 1321的文本。http://www.ietf.org/rfc/rfc1321.txt 实现策略 MD5的算法在RFC1321中实际上已经提供了C的实现,我们其实马上就能想到,至少有两种用Java实现它的方法,第一种是,用Java语言重新写整个算法,或者再说简单点就是把C程序改写成Java程序。第二种是,用JNI(Java Native Interface)来实现,核心算法仍然用这个C程序,用Java类给它包个壳。 但我个人认为,JNI应该是Java为了解决某类问题时的没有办法的办法(比如与操作系统或I/O设备密切相关的应用),同时为了提供和其它语言的互操作性的一个手段。使用JNI带来的最大问题是引入了平台的依赖性,打破了SUN所鼓吹的“一次编写到处运行”的Java好处。因此,我决定采取第一种方法,一来和大家一起尝试一下“一次编写到处运行”的好处,二来检验一下Java 2现在对于比较密集的计算的效率问题。 实现过程 限于这篇文章的篇幅,同时也为了更多的读者能够真正专注于问题本身,我不想就某一种Java集成开发环境来介绍这个Java Bean的制作过程,介绍一个方法时我发现步骤和命令很清晰,我相信有任何一种Java集成环境三天以上经验的读者都会知道如何把这些代码在集成环境中编译和运行。用集成环境讲述问题往往需要配很多屏幕截图,这也是我一直对集成环境很头疼的原因。我使用了一个普通的文本编辑器,同时使用了Sun公司标准的JDK 1.3.0 for Windows NT。 其实把C转换成Java对于一个有一定C语言基础的程序员并不困难,这两个语言的基本语法几乎完全一致.我大概花了一个小时的时间完成了代码的转换工作,我主要作了下面几件事: 把必须使用的一些#define的宏定义变成Class中的final static,这样保证在一个进程空间中的多个Instance共享这些数据 删去了一些无用的#if define,因为我只关心MD5,这个推荐的C实现同时实现了MD2 MD3和 MD4,而且有些#if define还和C不同编译器有关 将一些计算宏转换成final static 成员函数。 所有的变量命名与原来C实现中保持一致,在大小写上作一些符合Java习惯的变化,计算过程中的C函数变成了private方法(成员函数)。 关键变量的位长调整 定义了类和方法 需要注意的是,很多早期的C编译器的int类型是16 bit的,MD5使用了unsigned long int,并认为它是32bit的无符号整数。而在Java中int是32 bit的,long是64 bit的。在MD5的C实现中,使用了大量的位操作。这里需要指出的一点是,尽管Java提供了位操作,由于Java没有unsigned类型,对于右移位操作多提供了一个无符号右移:>>>,等价于C中的 >> 对于unsigned 数的处理。 因为Java不提供无符号数的运算,两个大int数相加就会溢出得到一个负数或异常,因此我将一些关键变量在Java中改成了long类型(64bit)。我个人认为这比自己去重新定义一组无符号数的类同时重载那些运算符要方便,同时效率高很多并且代码也易读,OO(Object Oriented)的滥用反而会导致效率低下。 限于篇幅,这里不再给出原始的C代码,有兴趣对照的读者朋友可以去看RFC 1321。MD5.java源代码 测试 在RFC 1321中,给出了Test suite用来检验你的实现是否正确: MD5 ("") = d41d8cd98f00b204e9800998ecf8427e MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661 MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72 MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0 MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b …… 这些输出结果的含义是指:空字符串””的MD5值是d41d8cd98f00b204e9800998ecf8427e,字符串”a”的MD5值是0cc175b9c0f1b6a831c399e269772661…… 编译并运行我们的程序: javac –d . MD5.java java beartool.MD5 为了将来不与别人的同名程序冲突,我在我的程序的第一行使用了package beartool; 因此编译命令javac –d . MD5.java 命令在我们的工作目录下自动建立了一个beartool目录,目录下放着编译成功的 MD5.class 我们将得到和Test suite同样的结果。当然还可以继续测试你感兴趣的其它MD5变换,例如: java beartool.MD5 1234 将给出1234的MD5值。 可能是我的计算机知识是从Apple II和Z80单板机开始的,我对大写十六进制代码有偏好,如果您想使用小写的Digest String只需要把byteHEX函数中的A、B、C、D、E、F改成a、b、 c、d、e、f就可以了。 MD5据称是一种比较耗时的计算,我们的Java版MD5一闪就算出来了,没遇到什么障碍,而且用肉眼感觉不出来Java版的MD5比C版的慢。 为了测试它的兼容性,我把这个MD5.class文件拷贝到我的另一台Linux+IBM JDK 1.3的机器上,执行后得到同样结果,确实是“一次编写到处运行了”。 Java Bean简述 现在,我们已经完成并简单测试了这个Java Class,我们文章的标题是做一个Java Bean。 其实普通的Java Bean很简单,并不是什么全新的或伟大的概念,就是一个Java的Class,尽管 Sun规定了一些需要实现的方法,但并不是强制的。而EJB(Enterprise Java Bean)无非规定了一些必须实现(非常类似于响应事件)的方法,这些方法是供EJB Container使用(调用)的。 在一个Java Application或Applet里使用这个bean非常简单,最简单的方法是你要使用这个类的源码工作目录下建一个beartool目录,把这个class文件拷贝进去,然后在你的程序中import beartool.MD5就可以了。最后打包成.jar或.war是保持这个相对的目录关系就行了。 Java还有一个小小的好处是你并不需要摘除我们的MD5类中那个main方法,它已经是一个可以工作的Java Bean了。Java有一个非常大的优点是她允许很方便地让多种运行形式在同一组代码中共存,比如,你可以写一个类,它即是一个控制台Application和GUI Application,同时又是一个Applet,同时还是一个Java Bean,这对于测试、维护和发布程序提供了极大的方便,这里的测试方法main还可以放到一个内部类中,有兴趣的读者可以参考:http://www.cn.ibm.com/developerWorks/java/jw-tips/tip106/index.shtml 这里讲述了把测试和示例代码放在一个内部静态类的好处,是一种不错的工程化技巧和途径。 把Java Bean装到JSP里 正如我们在本文开头讲述的那样,我们对这个MD5 Bean的应用是基于一个用户管理,这里我们假设了一个虚拟社区的用户login过程,用户的信息保存在数据库的个名为users的表中。这个表有两个字段和我们的这个例子有关,userid :char(20)和pwdmd5 :char(32),userid是这个表的Primary Key,pwdmd5保存密码的MD5串,MD5值是一个128bit的大整数,表示成16进制的ASCII需要32个字符。 这里给出两个文件,login.html是用来接受用户输入的form,login.jsp用来模拟使用MD5 Bean的login过程。 为了使我们的测试环境简单起见,我们在JSP中使用了JDK内置的JDBC-ODBC Bridge Driver,community是ODBC的DSN的名字,如果你使用其它的JDBC Driver,替换掉login.jsp中的 Connection con= DriverManager.getConnection("jdbc:odbc:community", "", ""); 即可。 login.jsp的工作原理很简单,通过post接收用户输入的UserID和Password,然后将Password变换成MD5串,然后在users表中寻找UserID和pwdmd5,因为UserID是users表的Primary Key,如果变换后的pwdmd5与表中的记录不符,那么SQL查询会得到一个空的结果集。 这里需要简单介绍的是,使用这个Bean只需要在你的JSP应用程序的WEB-INF/classes下建立一个beartool目录,然后将MD5.class拷贝到那个目录下就可以了。如果你使用一些集成开发环境,请参考它们的deploy工具的说明。在JSP使用一个java Bean关键的一句声明是程序中的第2行: 这是所有JSP规范要求JSP容器开发者必须提供的标准Tag。 id=实际上是指示JSP Container创建Bean的实例时用的实例变量名。在后面的<%和%>之间的Java程序中,你可以引用它。在程序中可以看到,通过 pwdmd5=oMD5.getMD5ofStr (password)引用了我们的MD5 Java Bean提供的唯一一个公共方法: getMD5ofStr。 Java Application Server执行.JSP的过程是先把它预编译成.java(那些Tag在预编译时会成为java语句),然后再编译成.class。这些都是系统自动完成和维护的,那个.class也称为Servlet。当然,如果你愿意,你也可以帮助Java Application Server去干本该它干的事情,自己直接去写Servlet,但用Servlet去输出HTML那简直是回到了用C写CGI程序的恶梦时代。 如果你的输出是一个复杂的表格,比较方便的方法我想还是用一个你所熟悉的HTML编辑器编写一个“模板”,然后在把JSP代码“嵌入”进去。尽管这种JSP代码被有些专家指责为“空心粉”,它的确有个缺点是代码比较难管理和重复使用,但是程序设计永远需要的就是这样的权衡。我个人认为,对于中、小型项目,比较理想的结构是把数据表示(或不严格地称作WEB界面相关)的部分用JSP写,和界面不相关的放在Bean里面,一般情况下是不需要直接写Servlet的。 如果你觉得这种方法不是非常的OO(Object Oriented),你可以继承(extends)它一把,再写一个bean把用户管理的功能包进去。 到底能不能兼容? 我测试了三种Java应用服务器环境,Resin 1.2.3、Sun J2EE 1.2、IBM WebSphere 3.5,所幸的是这个Java Bean都没有任何问题,原因其实是因为它仅仅是个计算程序,不涉及操作系统,I/O设备。其实用其它语言也能简单地实现它的兼容性的,Java的唯一优点是,你只需提供一个形态的运行码就可以了。请注意“形态”二字,现在很多计算结构和操作系统除了语言本身之外都定义了大量的代码形态,很简单的一段C语言核心代码,转换成不同形态要考虑很多问题,使用很多工具,同时受很多限制,有时候学习一种新的“形态”所花费的精力可能比解决问题本身还多。比如光Windows就有EXE、Service、的普通DLL、COM DLL以前还有OCX等等等等,在Unix上虽说要简单一些,但要也要提供一个.h定义一大堆宏,还要考虑不同平台编译器版本的位长度问题。我想这是Java对我来说的一个非常重要的魅力吧。 MD5算法说明 一、补位 二、补数据长度 三、初始化MD5参数 四、处理位操作函数 五、主要变换过程 六、输出结果 补位: MD5算法先对输入的数据进行补位,使得数据位长度LEN对512求余的结果是448。即数据扩展至K*512+448位。即K*64+56个字节,K为整数。 具体补位操作:补一个1,然后补0至满足上述要求。 补数据长度: 用一个64位的数字表示数据的原始长度B,把B用两个32位数表示。这时,数 据就被填补成长度为512位的倍数。 初始化MD5参数: 四个32位整数 (A,B,C,D) 用来计算信息摘要,初始化使用的是十六进制表 示的数字 A=0X01234567 B=0X89abcdef C=0Xfedcba98 D=0X76543210 处理位操作函数: X,Y,Z为32位整数。 F(X,Y,Z) = X&Y|NOT(X)&Z G(X,Y,Z) = X&Z|Y?(Z) H(X,Y,Z) = X xor Y xor Z I(X,Y,Z) = Y xor (X|not(Z)) 主要变换过程: 使用常数组T[1 ... 64], T[i]为32位整数用16进制表示,数据用16个32位 的整数数组M[]表示。 具体过程如下: /* 处理数据原文 */ For i = 0 to N/16-1 do /*每一次,把数据原文存放在16个元素的数组X中. */ For j = 0 to 15 do Set X[j] to M[i*16+j]. end /结束对J的循环 /* Save A as AA, B as BB, C as CC, and D as DD. */ AA = A BB = B CC = C DD = D /* 第1轮*/ /* 以 [abcd k s i]表示如下操作 a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ /* Do the following 16 operations. */ [ABCD 0 7 1] [DABC 1 12 2] [CDAB 2 17 3] [BCDA 3 22 4] [ABCD 4 7 5] [DABC 5 12 6] [CDAB 6 17 7] [BCDA 7 22 8] [ABCD 8 7 9] [DABC 9 12 10] [CDAB 10 17 11] [BCDA 11 22 12] [ABCD 12 7 13] [DABC 13 12 14] [CDAB 14 17 15] [BCDA 15 22 16] /* 第2轮* */ /* 以 [abcd k s i]表示如下操作 a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ /* Do the following 16 operations. */ [ABCD 1 5 17] [DABC 6 9 18] [CDAB 11 14 19] [BCDA 0 20 20] [ABCD 5 5 21] [DABC 10 9 22] [CDAB 15 14 23] [BCDA 4 20 24] [ABCD 9 5 25] [DABC 14 9 26] [CDAB 3 14 27] [BCDA 8 20 28] [ABCD 13 5 29] [DABC 2 9 30] [CDAB 7 14 31] [BCDA 12 20 32] /* 第3轮*/ /* 以 [abcd k s i]表示如下操作 a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ /* Do the following 16 operations. */ [ABCD 5 4 33] [DABC 8 11 34] [CDAB 11 16 35] [BCDA 14 23 36] [ABCD 1 4 37] [DABC 4 11 38] [CDAB 7 16 39] [BCDA 10 23 40] [ABCD 13 4 41] [DABC 0 11 42] [CDAB 3 16 43] [BCDA 6 23 44] [ABCD 9 4 45] [DABC 12 11 46] [CDAB 15 16 47] [BCDA 2 23 48] /* 第4轮*/ /* 以 [abcd k s i]表示如下操作 a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ /* Do the following 16 operations. */ [ABCD 0 6 49] [DABC 7 10 50] [CDAB 14 15 51] [BCDA 5 21 52] [ABCD 12 6 53] [DABC 3 10 54] [CDAB 10 15 55] [BCDA 1 21 56] [ABCD 8 6 57] [DABC 15 10 58] [CDAB 6 15 59] [BCDA 13 21 60] [ABCD 4 6 61] [DABC 11 10 62] [CDAB 2 15 63] [BCDA 9 21 64] /* 然后进行如下操作 */ A = A + AA B = B + BB C = C + CC D = D + DD end /* 结束对I的循环*/ 输出结果。 <淘宝热门商品:
 

9.80 元  

恒睿日本长筒棉袜批发网

疯狂促销 韩国进口复古百搭格子围巾风扉全球明星必备 只要9.8

 

运动鞋 

X-2品牌时尚鞋城【郭氏鞋坊旗下】[销售出口多余产品

来源:程序员网

小小豆叮

再译:使用struts+spring+hibernate 组装web应用

再译:使用struts+spring+hibernate 组装web应用   原作者: Mark Eagle 04/07/2004( http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html )   译者:孟大兴 来自学习日记( http://www.learndiary.com ) 联系方式:mdx-xx@tom.com   [译者前言:这篇文章由totodo在2004-09-16已经翻译过( http://www.matrix.org.cn/resource/article/1034.html ),本译文借鉴了不少他的成果。希望各位朋友指出我译文中的不足,并能根据上面的联系方式及时反馈给我,我将第一时间内在Matrix我的blog中更新译文( http://blog.matrix.org.cn/page/littlebat?entry=%E5%86%8D%E8%AF%91_%E4%BD%BF%E7%94%A8struts_spring_hibernate_%E7%BB%84%E8%A3%85web%E5%BA%94%E7%94%A8 ),争取为广大不熟悉英文的朋友提供尽可能准确的译文。另外,如果你在运行本文章的例程时碰到问题:请参考:1、原作者的网站上的答疑( http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?page=3 );2、我的试验文中的例程的日记( http://www.learndiary.com/disDiaryContentAction.do?goalID=1468 和 http://www.learndiary.com/disDiaryContentAction.do?goalID=1470 )]   其实,就算用Java建造一个不是很烦琐的web应用程序,也不是件轻松的事情。当为一个应用程序建造一个构架时有许多事情需要考虑。从高层来说,开发者需要考虑:怎样建立用户接口( user interfaces )?在哪里处理业务逻辑?和怎样持久化应用数据。这三层每一层都有它们各自的问题需要回答。 各个层次应该使用什么技术?怎样才能把应用程序设计得松耦合和能灵活改变?构架允许层的替换不会影响到其它层吗?应用程序怎样处理容器级的服务( container level services ),比如事务处理( transactions )?   当为你的web应用程序创建一个构架时,需要涉及到相当多的问题。幸运的是,已经有不少开发者已经遇到过这类重复发生的问题,并且建立了处理这类问题的框架。一个好框架具备以下几点: 减轻开发者处理复杂的问题的负担( “不重复发明轮子” );内部定义为可扩展的;有一个强大的用户群支持。框架通常能够很好的解决一方面的问题。然而,你的应用程序有几个层可能都需要它们各自的框架。就如解决你的用户接口( UI )问题时你就不应该把事务逻辑和持久化逻辑掺杂进来。例如,你不应该在控制器( controller )里面写jdbc代码,使它包含有业务逻辑,这不是控制器应该提供的功能。它应该是轻量级的,代理来自用户接口( UI )外的调用请求给其它服务于这些请求的应用层。好的框架自然的形成代码如何分布的指导。更重要的是,框架减轻开发者从头开始写像持久层这样的代码的痛苦,使他们专注于对客户来说很重要的应用逻辑。   这篇文章将讨论怎样组合几个著名的框架去做到松耦合的目的,怎样建立你的构架,怎样让你的各个应用层保持一致。富于挑战的是:组合这些框架使得每一层都以一种松耦合的方式彼此沟通,而与底层的技术无关。这篇文章将使用3种流行的开源框架来讨论组合框架的策略。表现层我们将使用Struts( http://jakarta.apache.org/struts );业务层我们将使用Spring( http://www.springframework.org/ );持久层使用Hibrenate( http://www.hibernate.org/ ).你也可以在你的应用程序中替换这些框架中的任何一种而得到同样的效果。图1展示了当这些框架组合在一起时从高层看是什么样子。 图1用Struts, Spring, 和 Hibernate框架构建的概览 ( http://www.onjava.com/onjava/2004/04/07/graphics/wiring.gif ) 应用程序的分层 ( Application Layering ) 大多数不复杂的web应用都能被分成至少4个各负其责的层次。这些层次是:表现层( presentation )、持久层( persistence )、业务层( business )、领域模型层( domain model )。每层在应用程序中都有明确的责任,不应该和其它层混淆功能。每一应用层应该彼此独立但要给他们之间放一个通讯接口。让我们从审视各个层开始,讨论这些层应该提供什么和不应该提供什么。 表现层 (The Presentation Layer)   在一个典型的web应用的一端是表现层。很多Java开发者也理解Struts所提供的。然而,太常见的是,他们把像业务逻辑之类的耦合的代码放进了一个org.apache.struts.Action。所以,让我们在像Struts这样一个框架应该提供什么上取得一致意见。这儿是Struts负责的: 为用户管理请求和响应; 提供一个控制器( controller )代理调用业务逻辑和其它上层处理; 处理从其它层掷出给一个Struts Action的异常; 为显示提供一个模型; 执行用户接口( UI )验证。 这儿是一些经常用Struts编写的但是却不应该和Struts表现层相伴的项目: 直接和数据库通讯,比如JDBC调用; 业务逻辑和与你的应用程序相关的验证; 事务管理; 在表现层中引入这种代码将导致典型耦合( type coupling )和讨厌的维护。 持久层 ( The Persistence Layer ) 在典型web应用的另一端是持久层。这通常是使事情迅速失控的地方。开发者低估了构建他们自己的持久层框架的挑战性。一般来说,机构内部自己写的持久层不仅需要大量的开发时间,而且还经常缺少功能和变得难以控制。有几个开源的“对象-关系映射”( ORM )框架非常解决问题。尤其是,Hibernate框架为java提供了"对象-关系持久化"( object-to-relational persistence )机制和查询服务。Hibernate对那些已经熟悉了SQL和JDBC API的Java开发者有一个适中的学习曲线。Hibernate持久对象是基于简单旧式Java对象( POJO )和Java集合( Java collections )。此外,使用Hibernate并不妨碍你正在使用的IDE。下面的列表包含了你该写在一个持久层框架里的代码类型: 查询相关的信息成为对象。Hibernate通过一种叫作HQL的面向对象( OO )的查询语言或者使用条件表达式API( expressive criteria API )来做这个事情。 HQL非常类似于SQL-- 只是把SQL里的table和columns用Object和它的fields代替。有一些新的专用的HQL语言成分要学;不过,它们容易理解而且文档做得好。HQL是一种使用来查询对象的自然语言,花很小的代价就能学习它。 保存、更新、删除储存在数据库中的信息。 像Hibernate这样的高级“对象-关系”映射( object-to-relational mapping )框架提供对大多数主流SQL数据库的支持,它们支持“父/子”( parent/child )关系、事务处理、继承和多态。 这儿是一些应该在持久层里被避免的项目: 业务逻辑应该在你的应用的一个高一些的层次里。持久层里仅仅允许数据存取操作。 你不应该把持久层逻辑( persistence logic )和你的表现层逻辑( presentation logic )搅在一起。避免像JSPs或基于servlet的类这些表现层组件里的逻辑和数据存取直接通讯。通过把持久层逻辑隔离进它自己的层,应用程序变得易于修改而不会影响在其它层的代码。例如:Hebernate能够被其它持久层框架或者API代替而不会修改在其它任何层的代码。 业务层( The Business Layer ) 在一个典型的web应用程序的中间的组件是业务层或服务层。从编码的视角来看,这个服务层是最容易被忽视的一层。不难在用户接口( UI )层或者持久层里找到散布在其中的这种类型的代码。这不是正确的地方,因为这导致了应用程序的紧耦合,这样一来,随着时间推移代码将很难维护。幸好,针对这一问题有好几种Frameworks存在。在这个领域两个最流行的框架是Spring和PicoContainer,它们叫作微容器( microcontainers ),你可以不费力不费神的把你的对象连在一起。所有这些框架都工作在一个简单的叫作“依赖注入”( dependency injection )( 也通称“控制反转”( inversion of control ) )的概念上。这篇文章将着眼于Spring的为指定的配置参数通过bean属性的setter注入( setter injection )的使用。Spring也提供了一个构建器注入( constructor injection )的复杂形式作为setter注入的一个替代。对象们被一个简单的XML文件连在一起,这个XML文件含有到像事务管理器( transaction management handler )、对象工厂( object factories )、包含业务逻辑的服务对象( service objects )、和数据存取对象( DAO )这些对象的引用( references )。 这篇文章的后面将用例子来把Spring使用这些概念的方法说得更清楚一些。业务层应该负责下面这些事情: 处理应用程序的业务逻辑和业务验证; 管理事务; 预留和其它层交互的接口; 管理业务层对象之间的依赖; 增加在表现层和持久层之间的灵活性,使它们互不直接通讯; 从表现层中提供一个上下文( context )给业务层获得业务服务( business services ); 管理从业务逻辑到持久层的实现。 领域模型层 ( The Domain Model Layer ) 最后,因为我们讨论的是一个不是很复杂的、基于web的应用程序,我们需要一组能在不同的层之间移动的对象。领域对象层由那些代表现实世界中的业务对象的对象们组成,比如:一份订单( Order )、订单项( OrderLineItem )、产品( Product )等等。这个层让开发者停止建立和维护不必要的数据传输对象( 或者叫作DTOs ),来匹配他们的领域对象。例如,Hibernate允许你把数据库信息读进领域对象( domain objects )的一个对象图,这样你可以在连接断开的情况下把这些数据显示到UI层。那些对象也能被更新和送回到持久层并在数据库里更新。而且,你不必把对象转化成DTOs,因为DTOs在不同的应用层间移动,可能在转换中丢失。这个模型使得Java开发者自然地以一种面向对象的风格和对象打交道,没有附加的编码。 结合一个简单的例子   既然我们已经从一个高的层次上理解了这些组件, 现在就让我们开始实践吧。在这个例子中,我们还是将合并Struts、Spring、Hibernate框架。每一个这些框架在一篇文章中都有太多的细节覆盖到。这篇文章将用一个简单的例子代码展示怎样把它们结合在一起,而不是进入每个框架的许多细节。示例应用程序将示范一个请求怎样跨越每一层被服务的。这个示例应用程序的一个用户能保存一个订单到数据库中和查看一个在数据库中存在的订单。进一步的增强可以使用户更新或删除一个存在的订单。   你可以下载这个应用的源码( http://www.onjava.com/onjava/2004/04/07/examples/wiring.zip )。   因为领域对象( domain objects )将和每一层交互,我们将首先创建它们。这些对象将使我们定义什么应该被持久化,什么业务逻辑应该被提供,和哪种表现接口应该被设计。然后,我们将配置持久层和用Hibernate为我们的领域对象( domain objects )定义“对象-关系”映射( object-to-relational mappings )。然后,我们将定义和配置我们的业务对象( business objects )。在有了这些组件后,我们就能讨论用Spring把这些层连在一起。最后,我们将提供一个表现层( presentation layer ),它知道怎样和业务服务层( business service layer )交流和知道怎样处理从其它层产生的异常( exceptions )。 领域对象层( Domain Object Layer ) 因为这些对象将和所有层交互,这也许是一个开始编码的好地方。这个简单的领域模型将包括一个代表一份订单( order )的对象和一个代表一个订单项( line item for an order )的对象。订单( order )对象将和一组订单项( a collection of line item )对象有一对多( one-to-many )的关系。例子代码在领域层有两个简单的对象: com.meagle.bo.Order.java: 包括一份订单( oder )的概要信息; com.meagle.bo.OrderLineItem.java: 包括一份订单( order )的详细信息; 考虑一下为你的对象选择包名,它将反映你的应用程序是怎样分层的。例如:简单应用的领域对象( domain objects )可以放进com.meagle.bo包[译者注:bo-business object?]。更多专门的领域对象将放入在com.meagle.bo下面的子包里。业务逻辑在com.meagle.service包里开始打包,DAO对象放进com.meagle.service.dao.hibernate包。对于forms和actions的表现类( presentation classes )分别放入com.meagle.action 和 com.meagle.forms包。准确的包命名为你的类提供的功能提供一个清楚的区分,使当故障维护时更易于维护,和当给应用程序增加新的类或包时提供一致性。 持久层配置( Persistence Layer Configuration ) 用Hibernate设置持久层涉及到几个步骤。第一步是进行配置持久化我们的领域业务对象( domain business objects )。因为我们用于领域对象( domain objects )持久化的Hibernate和POJOs一起工作( 此句原文:Since Hibernate works with POJOs we will use our domain objects for persistence. ),因此,订单和订单项对象包括的所有的字段的都需要提供getter和setter方法。订单对象将包括像ID、用户名、合计、和订单项这样一些字段的标准的JavaBean格式的setter和getter方法。订单项对象将同样的用JavaBean的格式为它的字段设置setter和getter方法。   Hibernate在XML文件里映射领域对象到关系数据库。订单和订单项对象将有两个映射文件来表达这种映射。有像XDoclet( http://xdoclet.sourceforge.net/ )这样的工具来帮助这种映射。Hibernate将映射领域对象到这些文件: Order.hbm.xml OrderLineItem.hbm.xml 你可以在WebContent/WEB-INF/classes/com/meagle/bo目录里找到这些生成的文件。配置Hibernate SessionFactory( http://www.hibernate.org/hib_docs/api/net/sf/hibernate/SessionFactory.html )使它知道是在和哪个数据库通信,使用哪个数据源或连接池,加载哪些持久对象。SessionFactory提供的Session( http://www.hibernate.org/hib_docs/api/net/sf/hibernate/Session.html )对象是Java对象和像选取、保存、更新、删除对象这样一些持久化功能间的翻译接口。我们将在后面的部分讨论Hibernate操作Session对象需要的SessionFactory配置。 业务层配置( Business Layer Configuration )   既然我们已经有了领域对象( domain objects ),我们需要有业务服务对象来执行应用逻辑、执行向持久层的调用、获得从用户接口层( UI layer )的请求、处理事务、处理异常。为了将所有这些连接起来并且易于管理,我们将使用Spring框架的bean管理方面( bean management aspect )。Spring使用“控制反转”( IoC ),或者“setter依赖注入”来把这些对象连好,这些对象在一个外部的XML文件中被引用。“控制反转”是一个简单的概念,它允许对象接受其它的在一个高一些的层次被创建的对象。使用这种方法,你的对象从必须创建其它对象中解放出来并降低对象耦合。   这儿是个不使用IoC的对象创建它的从属对象( object creating its dependencies without IoC )的例子,这导致紧的对象耦合:   图2:没有使用IoC的对象组织。对象A创建对象B和C( http://www.onjava.com/onjava/2004/04/07/graphics/nonioc.gif )。   这儿是一个使用IoC的例子,它允许对象在一个高一些层次被创建和传进另外的对象,所以另外的对象能直接使用现成的对象·[译者注:另外的对象不必再亲自创建这些要使用的对象]( allows objects to be created at higher levels and passed into objects so that they can use the implementations directly ):   图3:对象使用IoC组织。对象A包含setter方法,它们接受到对象B和C的接口。这也可以用对象A里的接受对象B和C的构建器完成( http://www.onjava.com/onjava/2004/04/07/graphics/ioc.gif )。 建立我们的业务服务对象( Building Our Business Service Objects )   我们将在我们的业务对象中使用的setter方法接受的是接口,这些接口允许对象的松散定义的实现,这些对象将被设置或者注入。在我们这个例子里我们将使我们的业务服务对象接受一个DAO去控制我们的领域对象的持久化。当我们在这篇文章的例子中使用Hibernate( While the examples in this article use Hibernate ),我们可以容易的转换到一个不同的持久框架的实现,通知Spring使用新的实现的DAO对象。你能明白编程到接口和使用“依赖注入”模式是怎样宽松耦合你的业务逻辑和你的持久化机制的。   这儿是业务服务对象的接口,它是一个DAO对象依赖的桩。( Here is the interface for the business service object that is stubbed for a DAO object dependency: ) public interface IOrderService { public abstract Order saveNewOrder(Order order) throws OrderException, OrderMinimumAmountException; public abstract List findOrderByUser( String user) throws OrderException; public abstract Order findOrderById(int id) throws OrderException; public abstract void setOrderDAO( IOrderDAO orderDAO); }   注意上面的代码有一个为DAO对象准备的setter方法。这儿没有一个getOrderDAO方法因为它不是必要的,因为不太有从外面访问连着的OrderDAO对象的需要。DAO对象将被用来和我们的持久层沟通。我们将用Spring把业务服务对象和DAO对象连在一起。因为我们编码到接口,我们不会紧耦合实现。 下一步是写我们的DAO实现对象。因为Spring有内建的对Hibernate的支持,这个例子DAO将继承HibernateDaoSupport( http://www.springframework.org/docs/api/org/springframework/orm/hibernate/support/HibernateDaoSupport.html )类,这使得我们容易取得一个到HibernateTemplate( http://www.springframework.org/docs/api/org/springframework/orm/hibernate/HibernateTemplate.html )类的引用,HibernateTemplate是一个帮助类,它能简化Hibernate Session的编码和处理HibernateExceptions。这儿是DAO的接口: public interface IOrderDAO { public abstract Order findOrderById( final int id); public abstract List findOrdersPlaceByUser( final String placedBy); public abstract Order saveOrder( final Order order); }   我们还有两个对象要和我们的业务层连在一起。这包括HibernateSessionFactory和一个TransactionManager对象。这在Spring配置文件里直接完成。Spring提供一个HibernateTransactionManager( http://www.springframework.org/docs/api/org/springframework/orm/hibernate/HibernateTransactionManager.html ),它将从工厂绑定一个Hibernate Session到一个线程来支持事务( 见ThreadLocal( http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ThreadLocal.html )获取更多的信息 )。这儿是HibernateSessionFactory和HibernateTransactionManager的Spring配置。 com/meagle/bo/Order.hbm.xml com/meagle/bo/OrderLineItem.hbm.xml net.sf.hibernate.dialect.MySQLDialect false C:/MyWebApps/.../WEB-INF/proxool.xml spring   每一个对象能被Spring配置里的一个标记引用。在这个例子里,bean “mySessionFactory”代表一个HibernateSessionFactory,bean “myTransactionManager”代表一个Hibernate transaction manager。注意transactionManger bean有一个叫作sessionFactory的属性元素。HibernateTransactionManager有一个为sessionFactory准备的setter和getter方法,它们是用来当Spring容器启动时的依赖注入。sessionFactory属性引用mySessionFactory bean。这两个对象现在当Spring容器初始化时将被连在一起。这种连接把你从为引用和创建这些对象而创建singleton对象和工厂中解放出来,这减少了你应用程序中的代码维护。mySessionFactory bean有两个属性元素,它们翻译成为mappingResources 和 hibernatePropertes准备的setter方法。通常,如果你在Spring之外使用Hibernate,这个配置将被保存在hibernate.cfg.xml文件中。不管怎样,Spring提供了一个便捷的方式--在Spring配置文件中合并Hibernate的配置。获得更多的信息查阅Spring API( http://www.springframework.org/docs/api/index.html )。 既然我们已经配置了我们的容器服务beans和把它们连在了一起,我们需要把我们的业务服务对象和我们的DAO对象连在一起。然后,我们需要把这些对象连接到事务管理器。 这是在Spring配置文件里的样子: PROPAGATION_REQUIRED,readOnly,-OrderException PROPAGATION_REQUIRED,-OrderException 图4是我们已经连在一起的东西的一个概览。它展示了每个对象是怎样相关联的和怎样被Spring设置进其它对象中。把这幅图和示例应用中的Spring配置文件对比查看它们之间的关系。 图4:这是Spring怎样将在这个配置的基础上装配beans( http://www.onjava.com/onjava/2004/04/07/graphics/spring_wiring.gif )。   这个例子使用一个TransactionProxyFactoryBean,它有一个为我们已经定义了的事务管理者准备的setter方法。这是一个有用的对象,它知道怎样处理声明的事务操作和你的服务对象。你可以通过transactionAttributes属性定义事务怎样被处理,transactionAttributes属性为方法名定义模式和它们怎样参与进一个事务。获得更多的关于在一个事务上配置隔离层和提交或回滚查阅TransactionAttributeEditor( http://www.springframework.org/docs/api/org/springframework/transaction/interceptor/TransactionAttributeEditor.html )。   TransactionProxyFactoryBean( http://www.springframework.org/docs/api/org/springframework/transaction/interceptor/TransactionProxyFactoryBean.html )类也有一个为一个target准备的setter,target将是一个到我们的叫作orderTarget的业务服务对象的引用( a reference )。 orderTarget bean定义使用哪个业务服务对象并有一个指向setOrderDAO()的属性。orderDAO bean将居于这个属性中,orderDAO bean是我们的和持久层交流的DAO对象。   还有一个关于Spring和bean要注意的是bean能以两种模式工作。这两种模式被定义为singleton和prototype。一个bean默认的模式是singleton,意味着一个共享的bean的实例将被管理。这是用于无状态操作--像一个无状态会话bean将提供的那样。当bean由Spring提供时,prototype模式允许创建bean的新实例。你应当只有在每一个用户都需要他们自己的bean的拷贝时才使用prototype模式。 提供一个服务定位器( Providing a Service Locator )   既然我们已经把我们的服务和我们的DAO连起来了,我们需要把我们的服务暴露给其它层。通常是一个像使用Struts或Swing这样的用户接口层里的代码来使用这个服务。一个简单的处理方法是使用一个服务定位器模式的类从一个Spring上下文中返回资源。这也可以靠引用bean ID通过Spring来直接完成。   这儿是一个在Struts Action中怎样配置一个服务定位器的例子: public abstract class BaseAction extends Action { private IOrderService orderService; public void setServlet(ActionServlet actionServlet) { super.setServlet(actionServlet); ServletContext servletContext = actionServlet.getServletContext(); WebApplicationContext wac = WebApplicationContextUtils. getRequiredWebApplicationContext( servletContext); this.orderService = (IOrderService) wac.getBean("orderService"); } protected IOrderService getOrderService() { return orderService; } } 用户接口层配置 ( UI Layer Configuration )   示例应用的用户接口层使用Struts框架。这儿我们将讨论当为一个应用分层时和Struts相关的部分。让我们从在struts-config.xml文件里检查一个Action配置开始。    Save New Order   SaveNewOrder Action被用来持久化一个用户从用户接口层提交的订单。这是一个典型的Struts Action;然而,注意这个action的异常配置。这些Exceptions为我们的业务服务对象也在Spring 配置文件(applicationContext-hibernate.xml)中配置了( 在transactionAttributes属性里 )。当这些异常被从业务层掷出我们能在我们的用户接口里恰当的处理它们。第一个异常,OrderException,当在持久层里保存订单对象失败时将被这个action使用。这将引起事务回滚和通过业务对象传递把异常传回给Struts层。OrderMinimumAmountException,在业务对象逻辑里的一个事务因为提交的订单达不到最小订单数量而失败也将被处理。然后,事务将回滚和这个异常能被用户接口层恰当的处理。   最后一个连接步骤是使我们的表现层和我们的业务层交互。这已经通过使用前面讨论的服务定位器来完成了。服务层充当一个到我们的业务逻辑和持久层的接口。这儿是 Struts中的SaveNewOrder Action可能怎样使用一个服务定位器调用一个业务方法: public ActionForward execute( ActionMapping mapping, ActionForm form, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws java.lang.Exception { OrderForm oForm = (OrderForm) form; // Use the form to build an Order object that // can be saved in the persistence layer. // See the full source code in the sample app. // Obtain the wired business service object // from the service locator configuration // in BaseAction. // Delegate the save to the service layer and // further upstream to save the Order object. getOrderService().saveNewOrder(order); oForm.setOrder(order); ActionMessages messages = new ActionMessages(); messages.add( ActionMessages.GLOBAL_MESSAGE, new ActionMessage( "message.order.saved.successfully")); saveMessages(request, messages); return mapping.findForward("success"); } 结论   这篇文章按照技术和架构覆盖了许多话题。从中而取出的主要思想是怎样更好的给你的应用程序分层:用户接口层、持久逻辑层、和其它任何你需要的应用层。这样可以解耦你的代码,允许添加新的代码组件,使你的应用在将来更易维护。这里覆盖的技术能很好的解决这类的问题。不管怎样,使用这样的构架可以让你用其他技术代替现在的层。例如,你也许不想使用Hibernate持久化。因为你在你的DAO对象中编码到接口,你能怎样使用其它的技术或框架,比如 iBATIS( http://www.ibatis.com/ ),作为一个替代是显而易见的。或者你可能用不同于Struts的框架替代你的UI层。改变UI层的实现不会直接影响你的业务逻辑层或者你的持久层。替换你的持久层不会影响你的UI逻辑或业务服务层。集成一个web应用其实也不是一件烦琐的工作,靠解耦你的各应用层和用适当的框架组成它,它能变得更容易处理。 Mark Eagle 是一位在MATRIX智囊团的高级软件工程师, Inc. in Atlanta, GA。 <淘宝热门商品:
 

 

【上海商盟】高更食品极美滋新奥尔良系列烧烤腌料皇冠旗舰店

 

运动鞋 

X-2品牌时尚鞋城【郭氏鞋坊旗下】[销售出口多余产品

来源:程序员网

小小豆叮

Restlet—一个用于Java的REST框架

Restlet 是一个新的开源项目,提供用户进行快速建立REST 结构风格(由Roy T. Fielding定义)的应用的功能。 REST是一种从一个网站得到信息的方式,是通过HTTP进行消息传递的SOAP 的可选方案。REST和网络服务一样,可让应用软件彼此沟通无碍。将REST技术应用于开放式网络服务最成功的例子是Amazon.com,该网站允许程序设计师使用Amazon的各种服务,设计电子商务应用程序。 由于REST的技术较为单纯,所以跑得更快,情有可原。在追求产能的激励下,花在SOAP的开销只会多不会少,不过多数时候,这类的经常性开支是物超所值的。 该开源项目的目标是带给开发者简单而有效率的REST结构。它包括两个部分,Restlet API 和Noelios Restlet Engine (NRE)。 下载地址:http://www.restlet.org/ <淘宝热门商品:
 

运动鞋 

X-2品牌时尚鞋城【郭氏鞋坊旗下】[销售出口多余产品

 

 

燕窝饼店-皇冠信誉.纯中药美白.丰胸.减肥.排毒饼干.美丽吃出来

来源:程序员网

小小豆叮

归纳:编写Java程序最容易犯的21种错误

1.Duplicated Code   代码重复几乎是最常见的异味了。他也是Refactoring的主要目标之一。代码重复往往来自于copy-and-paste的编程风格。与他相对应OAOO是一个好系统的重要标志。   2.Long method   它是传统结构化的“遗毒”。一个方法应当具有自我独立的意图,不要把几个意图放在一起。   3.Large Class   大类就是你把太多的责任交给了一个类。这里的规则是One Class One Responsibility.   4.Divergent Change   一个类里面的内容变化率不同。某些状态一个小时变一次,某些则几个月一年才变一次;某些状态因为这方面的原因发生变化,而另一些则因为其他方面的原因变一次。面向对象的抽象就是把相对不变的和相对变化相隔离。把问题变化的一方面和另一方面相隔离。这使得这些相对不变的可以重用。问题变化的每个方面都可以单独重用。这种相异变化的共存使得重用非常困难。   5.Shotgun Surgery   这正好和上面相反。对系统一个地方的改变涉及到其他许多地方的相关改变。这些变化率和变化内容相似的状态和行为通常应当放在同一个类中。   6.Feature Envy   对象的目的就是封装状态以及与这些状态紧密相关的行为。如果一个类的方法频繁用get 方法存取其他类的状态进行计算,那么你要考虑把行为移到涉及状态数目最多的那个类。   7.Data Clumps   某些数据通常像孩子一样成群玩耍:一起出现在很多类的成员变量中,一起出现在许多方法的参数中,这些数据或许应该自己独立形成对象。   8.Primitive Obsession   面向对象的新手通常习惯使用几个原始类型的数据来表示一个概念。譬如对于范围,他们会使用两个数字。对于Money,他们会用一个浮点数来表示。因为你没有使用对象来表达问题中存在的概念,这使得代码变的难以理解,解决问题的难度大大增加。好的习惯是扩充语言所能提供原始类型,用小对象来表示范围、金额、转化率、邮政编码等等。   9.Switch Statement   基于常量的开关语句是OO 的大敌,你应当把他变为子类、state或strategy.   10. Parallel Inheritance Hierarchies   并行的继承层次是shotgun surgery的特殊情况。因为当你改变一个层次中的某一个类时,你必须同时改变另外一个层次的并行子类。   11. Lazy Class   一个干活不多的类。类的维护需要额外的开销,如果一个类承担了太少的责任,应当消除它。   12. Speculative Generality   一个类实现了从未用到的功能和通用性。通常这样的类或方法唯一的用户是testcase.不要犹豫,删除它。   13. Temporary Field   一个对象的属性可能只在某些情况下才有意义。这样的代码将难以理解。专门建立一个对象来持有这样的孤儿属性,把只和他相关的行为移到该类。最常见的是一个特定的算法需要某些只有该算法才有用的变量。   14. Message Chain   消息链发生于当一个客户向一个对象要求另一个对象,然后客户又向这另一对象要求另一个对象,再向这另一个对象要求另一个对象,如此如此。这时,你需要隐藏分派。   15. Middle Man   对象的基本特性之一就是封装,而你经常会通过分派去实现封装。但是这一步不能走得太远,如果你发现一个类接口的一大半方法都在做分派,你可能需要移去这个中间人。   16. Inappropriate Intimacy   某些类相互之间太亲密,它们花费了太多的时间去砖研别人的私有部分。对人类而言,我们也许不应该太假正经,但我们应当让自己的类严格遵守禁欲主义。   17. Alternative Classes with Different Interfaces   做相同事情的方法有不同的函数signature,一致把它们往类层次上移,直至协议一致。   18. Incomplete Library Class   要建立一个好的类库非常困难。我们大量的程序工作都基于类库实现。然而,如此广泛而又相异的目标对库构建者提出了苛刻的要求。库构建者也不是万能的。有时候我们会发现库类无法实现我们需要的功能。而直接对库类的修改有非常困难。这时候就需要用各种手段进行Refactoring.   19. Data Class   对象包括状态和行为。如果一个类只有状态没有行为,那么肯定有什么地方出问题了。   20. Refused Bequest   超类传下来很多行为和状态,而子类只是用了其中的很小一部分。这通常意味着你的类层次有问题。   21. Comments   经常觉得要写很多注释表示你的代码难以理解。如果这种感觉太多,表示你需要Refactoring。 <淘宝热门商品:
 

 

【家倍乐床上笔记本电脑桌专利厂家批发零售店】

 

156.0元  

辉煌保健_保健品/粉粉/减肥产品/丰胸产品

来源:程序员网

小小豆叮

数组实现杨辉三角

//写一个终端输入类以便键盘输入需要数值 import java.io.*; public class ConsoleReader { private String temp; BufferedReader reader; public ConsoleReader() { reader = new BufferedReader(new InputStreamReader(System.in)); } public int getInt() { try { temp = reader.readLine(); } catch (IOException ex) { ex.printStackTrace(); } return Integer.parseInt(temp); } } //数组实现杨辉三角 import com.mfg.console.ConsoleReader; public class YanHui { int[][] a; public YanHui() { ConsoleReader console=new ConsoleReader(); System.out.print("请输入要求的杨辉三角的级数:"); int n=console.getInt(); a=new int[n][]; for(int i=0;i
 

4.00 元  

阳光网游挂机程序专业店

[自动发货]梦幻西游辅助脚本单开压镖+半自动跑商+单开打图日卡

 

¥:7.00 

极限特攻-新奇产品仓库    金秋时节好礼送不停 

创意小猪/手摇式LED手电/手动手电/LED手电

来源:程序员网

小小豆叮

超线程多核心下Java多线程编程技术分析

阅读提要:在引入Java多线程技术后,几乎所有应用程序的开发在性能上都得到了很大的改进。本文将通过探讨超线程技术以及新出现的多核心Intel处理器技术来分析这些线程技术是怎样成为Java编程的一个标准部分的。   一、Java环境下的多线程技术   构建线程化的应用程序往往会对程序带来重要的性能影响。例如,请考虑这样一个程序,它从磁盘读取大量数据并且在把它们写到屏幕之前处理这些数据(例如一个DVD播放器)。在一个传统的单线程程序(今天所使用的大多数客户端程序)上,一次只有一个任务执行,每一个这些活动分别作为一个序列的不同阶段发生。只有在一块已定义大小的数据读取完成时才能进行数据处理。因此,能处理数据的程序逻辑直到磁盘读操作完成后才得到执行。这将导致非常差的性能问题。   在一个多线程程序中,可以分配一个线程来读取数据,让另一个线程来处理数据,而让第三个线程把数据输送到图形卡上去。这三个线程可以并行运行;这样以来,在磁盘读取数据的同时仍然可以处理数据,从而提高了整体程序的性能。许多大量的示例程序都可以被设计来同时做两件事情以进一步提高性能。Java虚拟机(JVM)本身就是基于此原因广泛使用了多线程技术。   本文将讨论创建多线程Java代码以及一些进行并行程序设计的最好练习;另外还介绍了对开发者极为有用的一些工具和资源。篇幅所限,不可能全面论述这些问题,所以我想只是重点提一下极重要的地方并提供给你相应的参考信息。   二、线程化Java代码   所有的程序都至少使用一个线程。在C/C++和Java中,这是指用对main()的调用而启动的那个线程。另外线程的创建需要若干步骤:创建一个新线程,然后指定给它某种工作。一旦工作做完,该线程将自动被JVM所杀死。   Java提供两个方法来创建线程并且指定给它们工作。第一种方法是子类化Java的Thread类(在java.lang包中),然后用该线程的工作函数重载run()方法。下面是这种方法的一个示例: public class SimpleThread extends Thread {  public SimpleThread(String str) {   super(str);  }  public void run() {   for (int i = 0; i < 10; i++) {    System.out.println(i + " " + getName());    try {     sleep((long)(Math.random() * 1000));    } catch (InterruptedException e) {}   }   System.out.println("DONE! " + getName());  } }   这个类子类化Thread并且提供它自己的run()方法。上面代码中的函数运行一个循环来打印传送过来的字符串到屏幕上,然后等待一个随机的时间数目。在循环十次后,该函数打印"DONE!",然后退出-并由它杀死这个线程。下面是创建线程的主函数: public class TwoThreadsDemo {  public static void main (String[] args) {   new SimpleThread("Do it!").start();   new SimpleThread("Definitely not!").start();  } }   注意该代码极为简单:函数开始,给定一个名字(它是该线程将要打印输出的字符串)并且调用start()。然后,start()将调用run()方法。程序的结果如下所示: 0 Do it! 0 Definitely not! 1 Definitely not! 2 Definitely not! 1 Do it! 2 Do it! 3 Do it! 3 Definitely not! 4 Do it! 4 Definitely not! 5 Do it! 5 Definitely not! 6 Do it! 7 Do it! 6 Definitely not! 8 Do it! 7 Definitely not! 8 Definitely not! 9 Do it! DONE! Do it! 9 Definitely not! DONE! Definitely not!   正如你所看到的,这两个线程的输出结果纠合到一起。在一个单线程程序中,所有的"Do it!"命令将一起打印,后面跟着输出"Definitely not!"。   这个程序的不同运行将产生不同的结果。这种不确定性来源于两个方面:在循环中有一个随机的暂停;更为重要的是,因为线程执行时间没法保证。这是一个关键的原则。JVM将根据它自己的时间表运行这些进程(虚拟机一般支持尽可能快地运行这些线程,但是没法保证何时运行一个给定线程)。对于每个线程可以使一个优先级与之相关联以确保关键线程被JVM处理在次要的线程之前。   启动一个线程的第二种方法是使用一个实现Runnable接口的类-这个接口也定义在java.lang中。这个Runnable接口指定一个run()方法-然后该方法成为线程的主函数,类似于前面的代码。   现在,Java程序的一般风格是支持继承的接口。通过使用接口,一个类在后面仍然能够继承(子类化)-如果必要的话(例如,如果该类要在后面作为一个applet使用的话,就会发生这种情况)。   三、线程的含义   在采用多线程技术增强性能的同时,它也增加了程序内部运行的复杂性。这种复杂性主要是由线程之间的交互引起的。熟悉这些问题是很重要的,因为随着越来越多的核心芯片加入到Intel处理器中,要使用的线程数目也将相应地增长。如果在创建多线程程序时不能很好地理解这些问题,那么是调试时将很难发现错误。因此,让我们先看一下这些问题及其解决办法。   等待另一个线程完成:假定我们有一个整型数组要进行处理。我们可以遍历这个数组,每次一个整数并执行相应的操作。或,更高效地,我们可以建立多个线程,这样以来让每个线程处理数组的一部分。假定我们在开始下一步之前必须等待所有的线程结束。为了暂时同步线程之间的活动,这些线程使用了join()方法-它使得一个线程等待另一个线程的完成。加入的线程(线程B)等待被加入的线程(线程A)的完成。在join()中的一个可选的超时值使得线程B可以继续处理其它工作-如果线程A在给定的时间帧内还没有终止的话。这个问题将触及到线程的核心复杂性-等待线程的问题。下面我们将讨论这个问题。   在锁定对象上等待:假定我们编写一个航空公司座位分配系统。在开发这种大型的程序时,为每个连接到该软件的用户分配一个线程是很经常的,如一个线程对应一个机票销售员(在很大的系统中,情况并非总是如此)。如果有两个用户同时想分配同一个座位,就会出现问题。除非采取特殊的措施,否则一个线程将分配该座位而另一个线程将会在做相同的事情。两个用户都会认为他们在这趟航班上拥有一个分配的位子。   为了避免两个线程同时修改一样的数据项,我们让一个线程在修改数据前锁定数据项。用这种方法,当第二个线程开始作修改时,它将等待到第一个线程释放锁为止。当这种发生时,线程将会看到座位已被分配,而对于座位分配的请求就会失败。两个线程竞争分配座位的问题也就是著名的竞争条件问题,而当竞争发生时有可能导致系统的泄漏。为此,最好的办法就是锁定任何代码-该代码存取一个可由多个线程共同存取的变量。   在Java中存在好几种锁选择。其中最为常用的是使用同步机制。当一个方法的签名包含同步时,在任何给定时间只有一个线程能够执行这个方法。然后,当该方法完成执行时,对该方法的锁定即被解除。例如, protected synchronized int reserveSeat ( Seat seat_number ){  if ( seat_number.getReserved() == false ){   seat_number.setReserved();   return ( 0 );  }  else return ( -1 ); }   就是一个方法-在这种方法中每次只运行一个线程。这种锁机制就打破了上面所描述的竞争条件。   使用同步是处理线程间交互的几种方法中的一种。J2SE 5.0中添加了若干方便的方法来锁定对象。大多数这些方法可以在包java.util.concurrent.locks中找到-一旦你熟悉了Java线程,就应该对它进行详细的研究。   在锁机制解决了竞争条件的同时,它们也带来了新的复杂性。在这种情况下,最困难的问题就是死锁。假定线程A在等待线程B,并且线程B在等待线程A,那么这两个线程将永远被锁定-这正是术语死锁的意义。死锁问题可能很难判定,并且必须相当小心以确保在线程之间没有这种依赖性。   四、使用线程池   如前所提及,在线程完成执行时,它们将被JVM杀死而分配给它们的内存将被垃圾回收机制所回收。不断地创建和毁灭线程所带来的麻烦是它浪费了时钟周期,因为创建线程确实耗费额外的时间。一个通用的且最好的实现是在程序运行的早期就分配一组线程(称为一个线程池),然后在这些线程可用时再使用它们。通过使用这种方案,在创建时分配给一个线程指定的功能就是呆在线程池中并且等待分配一项工作。然后,当分配的工作完成时,该线程被返回到线程池。   J2SE 5.0引入了java.util.concurrent包-它包括了一个预先构建的线程池框架-这大大便利了上述方法的实现。有关Java线程池的更多信息及一部教程,请参见http://java.sun.com/developer/JDCTechTips/2004/tt1116.html#2。   在设计线程程序和线程池时,自然出现关于应该创建多少线程的问题。答案看你怎样计划使用这些线程。如果你基于分离的任务来用线程划分工作,那么线程的数目等于任务的数目。例如,一个字处理器可能使用一个线程用于显示(在几乎所有系统中的主程序线程负责更新用户接口),一个用于标记文档,第三个用于拼写检查,而第四个用于其它后台操作。在这种情况中,创建四个线程是理想的并且它们提供了编写该类软件的一个很自然的方法。   然而,如果程序-象早些时候所讨论的那个一样-使用多个线程来做类似的工作,那么线程的最佳数目将是系统资源的反映,特别是处理器上可执行管道的数目和处理器的数目的反映。在采用英特尔处理器超线程技术(HT技术)的系统上,当前在每个处理器核心上有两个执行管道。最新的多核心处理器在每个芯片上有两个处理器核心。英特尔指出将来的芯片有可能具有多个核心,大部分是因为额外的核心会带来更高的性能而不会从根本上增加热量或电量的消耗。因此,管道数将会越来越多。   照上面这些体系结构所作的算术建议,在一个双核心Pentium 4处理器系统上,可以使用四条执行管道并因此可以使用四个线程将会提供理想的性能。在一个双处理器英特尔Xeon?处理器的工作站上,理想的线程数目是4,因为目前Xeon芯片提供HT技术但是没提供多核心模型。你可以参考下面文档来了解这些新型处理器上的执行管道的数目(http://www.intel.com/cd/ids/developer/asmo-na/eng/196716.htm)。   五、小结   你当在平台上运行线程化的Java程序时,你将可能想要监控在处理器上的加载过程与线程的执行。最好的获得这些数据与管理JVM怎样处理并行处理的JVM之一是BEA的WebLogic JRockit。JRockit还有其它一些由来自于BEA和Intel公司的工程师专门为Intel平台设计和优化的优点。   不考虑你使用哪一种JVM,Intel的VTune Performance Analyzer将会给你一个关于JVM怎样执行你的代码的很深入的视图-这包括每个线程的性能瓶颈等。另外,Intel还提供了关于如何在Java环境下使用VTune Performance Analyzer的白皮书[PDF 2MB]。   总之,本文提供了线程在Java平台工作机理的分析。由于Intel还将继续生产HT技术的处理器并且发行更多的多核心芯片,所以想从这些多管道中得到性能效益的压力也会增加。并且,由于核心芯片数目的增加,管道的数目也将相应地增加。唯一的利用它们的优点的办法就是使用多线程技术,如在本文中所讨论的。并且Java多线程程序的优势也越来越明显。 <淘宝热门商品:
 

0.70 元  

滋补品专门店/雪蛤油 燕窝 低价运作拒绝暴利,令美丽不再昂贵!

 

9.80 元  

恒睿日本长筒棉袜批发网

疯狂促销 韩国进口复古百搭格子围巾风扉全球明星必备 只要9.8

来源:程序员网

小小豆叮

AJAX框架JSON-RPC-Java 1.0rc2 发布

AJAX框架JSON-RPC-Java 近日宣布JSON-RPC-Java 1.0rc2 发布。 JSON-RPC-Java 是一个用Java来实现动态JSON-RPC 的框架。利用它内置的一个轻级量JSON-RPC JavaScripIt客户端,可以让你透明地在JavaScript中调用Java代码。JSON-RPC-Java可运行在Servlet容器中,因此可以在一个基于JavaScript 与DHTML 的Web应用程序中利用它来直接调用普通Java方法与EJB方法。 报道中指出,该新版本中主要升级了References 和LocalArgResolvers 的文档。在ErrorInvocation callback 界面支持集群,修补了JSON-RPC JavaScript 客户端的bugs。 下载地址:http://freshmeat.net/projects/json-rpc-java/?branch_id=49217&release_id=214415 <淘宝热门商品:
 

5.00 元 

超人气面膜 平民价格 顶级效果

 

12.00 元  

08VIVI杂志推荐 风靡韩国牛仔感七分打底裤

来源:程序员网

小小豆叮

印度软件培训管用吗?

南方网讯 前不久,印度国家信息技术研究院(NIIT)与中国90家软件培训机构联合推出“万人软件英才网络版”培训工程。NIIT号称,该工程将在明年向业内输送1万名软件人才。而近两年内,另一家印度软件培训巨头阿普泰克,已在中国38个城市设立了76个培训中心,招收学员数达18000人。按照这个进度,明年将有接近3万名“印度培训工厂”出品的软件人才入市。    印度软件培训质量到底怎么样?用人单位对“印版”证书是否认可?   软件蓝领源于印度   在印度,有许多上千人甚至数千人的软件企业,他们把软件的一个个功能模块看成传统商品上的机器零件,各种员工分工明确,因此产生了大量从事流水线上工作的“软件蓝领”。    伴随蓝领概念在中国的兴起,国内软件人才奇缺的现象被提到了超乎寻常的高度,究竟国内软件企业需要多少不同层次的软件人才,这个缺口如何量化,至今没有权威的统计数据,至于漫天飞舞的多少多少万的噱头,显然是被软件培训市场投机份子无限放大、自我标榜的工具。    目前国内软件从业人员约40万人,其中专门从事软件技术工作的软件人员约25万人。因此对于现今软件行业,很难想象出每年40万的软件人才缺口是个什么样的概念,其中夹杂的水分和权威性令人质疑,当我们追根溯源考究其数据的源头时,指向的却是来自于印度培训机构的调查。    中国缺乏软件人才是事实,但对软件蓝领的需求被炒作扩大也是事实,对此,本报前几期的文章《一场虚火——软件蓝领培训热的背后》作过详细调查。    但这并不说明印度软件培训没有价值,事实上,它有很多地方比国内的培训强。   中国培训之软 与印度相比,中国软件培训到底软在哪里呢?    一、我国培养软件人才主要通过正规大学的学历教育,是“一条腿走路”。而印度等国则是学历教育与职业教育两条腿走路,即不仅有传统的、大学的学历教育,还通过行之有效的职业教育体系培训大批所谓“软件蓝领”,从事底层的基础编程工作。这类基础编程工作简单、枯燥,但是要求严格、规范,对于以外包为主的软件加工业尤其重要。一般高中毕业生、甚至初中毕业生经过一两年的培训就能胜任这类工作。    二、我国的计算机软件专业教育在国际化、标准化方面已经大大落后。    三、我国许多高校教材平均每5年才更新一次,许多计算机理论教材都是80386时代编写的,大大落后于国际软件业的发展。这也是大学生毕业后难以胜任软件企业要求的主要原因。与之相比,印度APTECH的教材每年更新一次。   印度培训有些什么内容?   相比中国软件培训,印度软件人才培养体制就显得更加实用。按照印度的教学法,培训课上传统的BASIC、PASCAL教学已经不存在了,学员直接学习C++,包括大量使用的网络软件学习,针对性、应用性非常强。经过这样的教育和培训,任何人都可以具备编程能力。而这个教育的优点是起点低,针对性强,可以为企业有效地降低软件编程人员的成本;此外,对于缺乏一技之长的学生而言,可以很快地掌握编程技术,成为未来不可或缺的人才。    在此以NIIT推出的CNIIT课程为例,与中国的学历教育、短期的培训课程班不同,其是一种全新的培训模式。它要求学员用一年全日制时间学完所有课程,快速成长,所学计算机专业课课时超出大学本科四年学生所学的专业课课时;更为重要的是,它的课程设计来源于每年世界各大软件公司反馈出来的技能需求,年年更新,时时针对市场,学成后学员可以掌握世界先进的电子商务和互联网技术,并享有职业安置服务。学生不需计算机专业背景,也没有年龄限制,目标人群主要是高中、高校学生和IT从业人员。    从NIIT的WEB程序员课程设置可以看到,为期156周以及两个学期的实习期,相当于读完一个本科。不过,得到NIIT授权的上海浦东软件培训中心NIIT人员告诉记者,只要不是智障,都可以参加培训。    那么,NIIT采用怎样的教学方法呢?NIIT采用独特的培训方法,即用基于榜样的学习方法(MCLA方法)来进行教学。MCLA是在专家引导下的独立解决实际问题的科学学习方法。整个学习是由许多小的教学循环组成。每个教学循环中首先是提出一个由IT行业或工业界提出的实际问题,然后由专家(也就是教师)系统地用他的推理和计划编制的方法来解决这个问题。然后对学生提出类似的另一个实际问题,学生可以参照专家的方法来解决问题。这是在专家指导下的实践。最后学生必须将所有这些知识综合地用到解决一个新的实际问题上,而且由学生自己独立完成。这就是无指导下的实践。    这些大概就是印度软件培训风靡中国的深层次的原因。上海NIIT培训透露,其本部二年合一年的培训项目招生120名,全部爆满。该培训按季度收费,每季度超过4000元,而每周仅仅15个小时的课程。    印度软件培训采取与中国培训机构合作的方式迅速扩张,渗透很深。不论是同印度最大的培训机构APTECH合资成立的北大青鸟软件培训还是AIIT同国内院校联盟打造的软件学院,抑或是鱼龙混杂的不规范的小机构投资者,无一不是通过“OEM″印度培训机制的贴牌产物,从统一教材、引入印度讲师、专家和培训体系,背后宣传的筹码无法摆脱印度的影子。   “印版”人才流向哪里?   “印版”软件人才能被接受吗?市场认可的,才是最硬的,记者采访了一些信息技术企业。    盟龙软件有限公司、上海欧瑞特软件有限公司这样的公司还没有使用“印版”人才。其中盟龙软件有限公司工作人员告诉记者,他们的总部在北京,有400号开发人员,但是,他们没有使用“印版”人才,而且也没有那个打算,原因很简单,北京拥有国内一半左右的软件人才,而且是最优秀的。    当采访深入下去的时候,结果让人大吃一惊。中软科技发展有限公司有关人员居然说:“我们有的是人才,不需要他们”。    PCEC恩埃埃悌信息技术学院的相关人员这样解释:可能是各公司的项目与NIIT的培训有时候衔接不起来,这个也不奇怪。然后,市场部王小姐告诉记者,原则上他们是要推荐工作的,1998年上海培训启动以来,他们有许多学员结业以后推荐到外企、国企等,比如上海银行、IBM等等,学制两年的是以大专毕业生的身份进入这些公司的。    不过,一某合作培训学校一女士说,不是所有的人都可以合格离开学校的,推荐工作更不可能了。并且,她拒绝透露合格率 <淘宝热门商品:
 

68.00 元 

超人气神奇魔水 柔嫩细滑肌肤一喷即成

 

16.00 元  

减肥极品魔芋胶

来源:程序员网

小小豆叮

Java修饰词的总结

Java语言定义了public、protected、private、abstract、static和final这6常用修饰词外还定义了5 个不太常用的修饰词,下面是对这11个Java修饰词的介绍: 1.public 使用对象:类、接口、成员 介绍:无论它所处在的包定义在哪,该类(接口、成员)都是可访问的 2.private 使用对象:成员 介绍:成员只可以在定义它的类中被访问 3.static 使用对象:类、方法、字段、初始化函数 介绍:成名为static的内部类是一个顶级类,它和包含类的成员是不相关的。静态方法是类方法, 是被指向到所属的类而不是类的实例。静态字段是类字段,无论该字段所在的类创建了多少实例,该字 段只存在一个实例被指向到所属的类而不是类的实例。初始化函数是在装载类时执行的,而不是在创建 实例时执行的。 4.final 使用对象:类、方法、字段、变量 介绍:被定义成final的类不允许出现子类,不能被覆盖(不应用于动态查询),字段值不允许被 修改。 5.abstract 使用对象:类、接口、方法 介绍:类中包括没有实现的方法,不能被实例化。如果是一个abstract方法,则方法体为空,该方 法的实现在子类中被定义,并且包含一个abstract方法的类必须是一个abstract类 6.protected 使用对象:成员 介绍:成员只能在定义它的包中被访问,如果在其他包中被访问,则实现这个方法的类必须是该成 员所属类的子类。 7.native 使用对象:成员 介绍:与操作平台相关,定义时并不定义其方法,方法的实现被一个外部的库实现。 8.strictfp 使用对象:类、方法 介绍:strictfp修饰的类中所有的方法都隐藏了strictfp修饰词,方法执行的所有浮点计算遵守 IEEE 754标准,所有取值包括中间的结果都必须表示为float或double类型,而不能利用由本地平台浮 点格式或硬件提供的额外精度或表示范围。 9.synchronized 使用对象:方法 介绍:对于一个静态的方法,在执行之前jvm把它所在的类锁定;对于一个非静态类的方法,执行 前把某个特定对象实例锁定。 10.volatile 使用对象:字段 介绍:因为异步线程可以访问字段,所以有些优化操作是一定不能作用在字段上的。volatile有时 可以代替synchronized。 11.transient 使用对象:字段 介绍:字段不是对象持久状态的一部分,不应该把字段和对象一起串起。 <淘宝热门商品:
 

288.00元  

【果然瘦身】(关于减肥药)瘦脸/瘦腿/小腰(专业指导你减肥)

 

¥:28.00 

冲三皇冠疯抢啦 亲亲baby快乐驿站,宝宝用品童鞋童帽童装

*皇冠特色*纯手工,可爱特别的老虎护耳帽宝宝帽子童帽,46-48cm

来源:程序员网

小小豆叮