Java语言相关的重要术语解析

Java,是一种解释型语言。由SUN公司开发,最初用于移动设备软件开发,结果却因为Internet的发展而成名。   Java 语言基本上属于一个完全面向对象的语言,并且语言的设计仍然以简捷为重点,因此有其它语言基础的朋友学习Java语言会感觉比较简单,对于这个语言学习的难点则是面向对象的相关概念,包括:包、类、对象、实例、接口、继承、重载与覆盖,还有就是类、变量、函数的相关作用域,这些是语言学习的重点和难点。   对于语言的学习可以参考《Java 2参考大全》,对于面向对象的学习可以参考《Think in Java》,先学语言打好基础,再学面向对象的概念以及设计,通过自己设计程序再进一步去了解设计模式,循序渐进地达到Java程序员的基本要求。   学习Java还有个非常重要的就是类库,因为没有人还会从头开发程序,SUN公司提供了一套完整的开发用的基础类库,如何用好这些类才是Java语言学习的重中之重。   JVM (Java Virtual Machine, Java虚拟机)。   就是Java程序运行的虚拟环境,因为Java是解释型的语言,因此需要一个边解释边运行的支撑环境。同时,JVM又是在OS(操作系统)之上的,对于在JVM上运行的Java程序提供了统一的标准接口,从而屏蔽了操作系统的差异性,实现了Java代码的“一次编写,处处运行”的承诺,这个解释说明。NET平台理论上也可以实现这个功能,只是微软没有提供这样的支持。   为了提升程序运行的效率以及代码知识产权的保护,Java代码会使用JDK中的编译器编译成字节码(中间代码),从而运行在JVM之上,但是这个编译结果与C/C++这种编译型语言编译出来的结果不同,Java编译出来的是一种结构中立的中间文件格式,只能在JVM上执行,而C/C++编译出来的已经是最终的执行程序,操作系统只是管理和支撑应用运行,但是编译出来的结果已经是机器码。因此Java的Class文件可以使用反编译工具转换成 Java代码进行分析,推荐的反编译工具是JAD及它的Eclise插件。   许多公司都有开发自己的JVM,据测试数据显示性能都比SUN提供的免费版本要好,但是我实际使用中没有发现明显地区别,而SUN也有高级但是收费的版本,因此性能上没有显示地提升还是使用免费地版本就可以了。   JRE(Java Runtime Environment,Java运行环境)。JRE提供了类库、JVM与其他组件来支持applet和Java应用程序的运行。另外,JRE拥有两个关键的发布技术:Java Plug-in与Java Web Start,Java Plug-in支持applet运行在大部分浏览器上,Java Web Start则可以将一个独立的应用程序发布到网络上。   JRE同时还是J2EE平台企业级应用开发与部署的支撑技术,但是不包括编译器与调试器等各种工具去支持applet和应用程序的开发。   Java Plug-in.这个技术是JRE的一部分,用于连接浏览器与Java平台。这个连接使得WEB站点的applets运行在客户端的浏览器中。   Java Web Start:只要拥有相同版本的JRE,独立的Java应用程序就可以通过这个技术发布到网络上。   JDK(Java Development Kit,Java开发工具)。   包括了Java运行环境(Java Runtime Envirnment),一堆Java工具和Java基础的类库(rt.jar),还有Java类库的源代码(src.zip)以及学习用的例子 (sample与demo)。为了使程序安装后就可以运行,许多Java应用服务器会集成JDK,原因可以参考我所写的《JRE与JDK在启动应用服务器中的作用》。   无论是JRE还是JDK最主要是使用他们携带的JVM,以及安装到JDK与JRE目录下的LIB目录里的JAR包。使用JRE还是 JDK都通过JAVA_HOME这个参数完成,而对LIB目录下的JAR包则通过CLASSPATH目录进行添加。值得注意的是如果JAVA_HOME设置成JDK的安装目录,实际上用的是包含在JDK安装目录下的JRE目录里的JVM.   JDK里面还包括了开发所需要用的编译、跟踪、发布等多种工具,这里就不一一描述,大家可以在网上查询资料,如果需要我这边补充,也可以跟帖说明。   J2SE( Java 2 Standard Edition, Java 2 标准版)。   Java 2平台标准版(现在叫Java SE)支持客户端和服务器端的Java应用程序开发,如今还包括了嵌入式和实时系统环境。Java SE还支持Java Web Services的开发,并且还是Java EE平台的基础。   Java SE平台中有两个主要的产品就是JRE与JDK.   J2EE( Java 2 Enterprise Edition, Java 2 企业版)。   J2EE(现在叫Java EE)是一种工业标准,用于支持可移植、可扩展、健壮并安全的服务器端Java程序。Java EE提供了web服务、组件模型、管理和通讯API从而可以实现符合工业标准SOA框架与WEB应用程序。Java EE平台包括符合Java EE规范的应用服务器,以及相关的工具、例子及帮助文件。还有符合Java EE标准的应用程序的发布与调试工具。   简单来说Java EE就是一组规范组成的,这些规范合成到一起组成一个技术标准。这个标准现在是由JCP组织制定,最新的版本是2006年6月发布的Java EE 5.0,所有的应用服务器产品都希望通过这样的认证。因为所有认证过的产品从理论上讲符合J2EE规范开发的应用程序都可以平滑地移植,现实中我做的移植工作也只需要修改不到5%的内容,并且大多是XML配置文件而不涉及到源代码。这样的好处使用户无须绑定到某个厂商的平台上,也为扩展这个市场打下了基础。   Java EE 5.0的认证过程是必须通过SUN公司提供的软件测试包,测试包里面包括了27000多个功能点的验证,验证通过后就可以获得这个标志,并且会在SUN的网站上挂出。http://java.sun.com/javaee/overview/compatibility.jsp   在2006年12月Apusic 5.0全球第四家通过了这个认证,这个事实也就说明中国的应用服务器产品终于在技术上没有了差距,甚至因为Apusic研发产品的态度专注,所以还领先了国外的主要竞争对手。   Java EE SDK就是SUN公司开发的一个符合J2EE标准的应用服务器,可以下载后免费使用来了解Java EE的最新技术,当然也可以下载Apusic 5.0这个也是符合Java EE最新标准的产品,而且会有更加友好的中文界面与中文帮助。   写的过程中,总觉得知识点都在相互关联着,于是写出来的东西好像会越来越多,无法收笔。因此,希望看过的朋友多给提宝贵意见,使我写的东西更加有针对性,能够为学习和使用J2EE技术的朋友,以及使用我们Apusic产品的客户带来收获。 <淘宝热门商品:
 

¥:38.00 

[郭氏鞋坊旗下]四季兜外贸童鞋店

185黑黄 库存外贸 DISNEY/迪斯尼Tigger&pooh童休闲运动鞋 带闪灯

 

¥:29.00 

‖ 淘时尚 ‖入托名字条‖布质可烫可缝‖姓名贴‖

‖四钻‖棉质耐洗‖全彩色免缝姓名条 熨烫入托名字条 迪斯尼

来源:程序员网

小小豆叮

定时执行任务的三种方法

1)java.util.Timer 这个方法应该是最常用的,不过这个方法需要手工启动你的任务: Timer timer=new Timer(); timer.schedule(new ListByDayTimerTask(),10000,86400000); 这里的ListByDayTimerTask类必须extends TimerTask里面的run()方法。 2)ServletContextListener 这个方法在web容器环境比较方便,这样,在web server启动后就可以 自动运行该任务,不需要手工操作。 将ListByDayListener implements ServletContextListener接口,在 contextInitialized方法中加入启动Timer的代码,在contextDestroyed 方法中加入cancel该Timer的代码;然后在web.xml中,加入listener: < listener> < listener-class>com.qq.customer.ListByDayListener< /listener-class> < /listener> 3)org.springframework.scheduling.timer.ScheduledTimerTask 如果你用spring,那么你不需要写Timer类了,在schedulingContext-timer .xml中加入下面的内容就可以了: < ?xml version="1.0" encoding="UTF-8"?> < !DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> < beans> < bean id="timer" class="org.springframework.scheduling.timer.TimerFactoryBean"> < property name="scheduledTimerTasks"> < list> < ref local="MyTimeTask1"/> < /list> < /property> < /bean> < bean id="MyTimeTask" class="com.qq.timer.ListByDayTimerTask"/> < bean id="MyTimeTask1" class="org.springframework.scheduling.timer.ScheduledTimerTask"> < property name="timerTask"> < ref bean="MyTimeTask"/> < /property> < property name="delay"> < value>10000< /value> < /property> < property name="period"> < value>86400000< /value> < /property> < /bean> < /beans> <淘宝热门商品:
 

¥:78.00 

皇冠舒友阁 顶级特效美容护肤 效果才是硬道理

皇冠热销 印疤修复液 消除深浅痘印等色印、有效改善凹凸疤痕

 

¥:50.00 

【北京同仁堂国药】

来源:程序员网

小小豆叮

如何在JBOSS Server上发布EJB

1.准备文件 需要的软件:JDK1.3(for WIN) ,J2EE_1_2_1_SDK,JBoss2.0(www.jboss.org) 需要的文档:J2EE_1_2_1_SDK_DOC,Devguide1_2_1 2.准备环境 安装JDK1.3(支持JBOSS),装完后检查一下环境变量,可以编译运行一个小程序试一下. 安装JBOSS2.0,完成后运行bin un.bat试一下.JNDI 端口是1099,WEB端口是8080,可以用浏览器试一下,1099端口会返回一段乱码,8080端口返回空. 3.编译和打包 按照JavaTM 2 Enterprise Edition Developer´s Guide (v1.2.1)的Getting Started章中说的编译例子程序 ConverterEJB,然后用Deploy Tool打包生成 ConverterApp.ear. 用jar -xvf ConverterApp.ear 从中抽取 ejb-jar-ic.jar 这是打包好的和Bean有关的三个文件和工具生成meta-info*.xml文件(所谓的deployment descriptor). 然后运行JBoss的Deploy Tool打开ejb-jar-ic.jar,设置JNDI Name为MyConverter.然后保存.(该工具会自动生成JBoss的Deployment descriptor) 在把ejb-jar-ic.jar拷到jbossdeploy目录下,jboss会自动发布该Bean.. 4.运行客户端程序测试 按照JBoss的教学文档,修改 ConverterClient.java为 import javax.naming.*; import java.util.Hashtable; import javax.rmi.PortableRemoteObject; import java.util.Properties; import java.io.FileInputStream; import javax.rmi.PortableRemoteObject; import Converter; import ConverterHome; public class ConverterClient { public static void main(String[] args) { try { Properties props = new Properties(); Properties sysProps = System.getProperties(); try { props.load (new FileInputStream ("test.properties")); sysProps.putAll(props); } catch (Exception e) { System.err.println ("Can´t read `test.proprties´"); System.exit (-1); } System.setProperties (sysProps); Context initial = new InitialContext(); Object objref = initial.lookup("MyConverter"); ConverterHome home = (ConverterHome)PortableRemoteObject.narrow(objref, ConverterHome.class); Converter currencyConverter = home.create(); double amount = currencyConverter.dollarToYen(200.00); System.out.println(String.valueOf(amount)); amount = currencyConverter.yenToEuro(200.00); System.out.println(String.valueOf(amount)); } catch (Exception ex) { System.err.println("Caught an unexpected exception!"); ex.printStackTrace(); } } } test.properties文件内容如下 java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory java.naming.provider.url=xxx.xxx.xxx.xxx:1099 (写上JBoss所在机器的IP) 然后运行CompileClient.bat和TestClient.bat,就可以享受成功的喜悦了. <淘宝热门商品:
 

 

靓之彩数码影像:柯达数码冲印 刷照片冲印 水晶版画相册 冲洗彩扩

 

188.00 元  

地球都踩在脚下

T-MAC8麦迪8代 麦8 08-09赛季麦迪篮球鞋 白黑红 阿迪达斯adidas

来源:程序员网

小小豆叮

用RMI和CORBA进行分布式Java编程

Java远程方法调用(RMI)机制和公用对象请求代理体系(CORBA)是最重要 和使用最广泛的两种分布式对象系统。每个系统都有其特点和短处。它们在行 业中被用于从电子交易到保健医疗的各个领域。一个项目如果要从这两种分布式 机制中选用一个,往往难以抉择。本文概括地介绍了RMI和CORBA,更重要的是, 它将介绍如何开发一个有用的应用程序,用于从远程主机下载文件。然后它将: 简要介绍分布式对象系统 简要介绍RMI和CORBA 让你对在RMI和CORBA中开发应用程序所涉及的工作有个初步印象 演示如何使用RMI和CORBA,从远程主机传送文件 对RMI和CORBA进行简单比较 客户机/服务器模型 客户机/服务器模型是分布式计算的一种形式,在这种形式中,一个程序(客 户机)与另一个程序(服务器)通讯以便交换信息。在这种模型中,客户机和服 务器通常都说同样的语言--也就是说客户机和服务器能理解同一个协议--这 样它们才能通讯。 虽然客户机/服务器模型的实现方式多种多样,但典型做法是使用底层套接字。 使用套接字开发客户机/服务器系统意味着,我们必须设计一个协议,也就是客户 机和服务器都认识的一组命令集,通过这些命令它们就能通讯了。举例来说, HTTP协议中提供了一个名为GET的方法,所有Web服务器都必须实现这个方法,所 有Web客户机(浏览器)都必须使用这个方法,才能获取文档。 分布式对象模型 基于分布式对象的系统是一组对象的集合,这些对象以一种明确定义封装的接 口把服务的请求者(客户机)和服务的提供者(服务器)分隔开。换言之,客户 机从服务的实现中分离出来,变成数据的呈现和可执行代码。这就是基于分布式 对象的模型与纯粹的客户机/服务器模型的主要区别之一。 在基于分布式对象的模型中,客户机向对象发送消息,然后对象解释该消息以 便决定要执行什么服务。这项服务,也就是方法,可以选择是让对象还是让代理 来执行。Java远程方法调用(RMI)和公用对象请求代理体系(CORBA)就是这种 模型的例子。 RMI RMI是一个分布式对象系统,它使你能够轻松地开发出分布式Java应用程序。 在RMI中开发分布式应用程序比用套接字开发要简单,因为不需要做设计协议这种 很容易出错的工作。在RMI中,开发者会有一种错觉,似乎是从本地类文件调用的 本地方法,其实参数传送给了远程目标,目标解释参数后再把结果发回给调用方。 RMI应用程序初步 使用RMI开发分布式应用程序包括以下步骤: 定义一个远程接口 实现这个远程接口 开发服务器 开发客户机 生成存根和基干,启动RMI注册表、服务器和客户机 下面我们将通过开发一个文件传输程序来实践这些步骤。 范例: 文件传输程序 这个应用程序允许客户机从远程主机上传送(即下载)任何类型的文件(纯 文本或二进制文件)。第一步是定义一个远程接口,这个接口规定了服务器所提 供方法的信号,客户机将调用这些方法。 定义一个远程接口 用于文件下载应用程序的远程接口如代码范例1所示。接口 FileInterface提供了一个方法downloadFile,这个 方法接受String参数(文件名),将文件的数据以字节数组的形式 返回。 代码范例1 1: FileInterface.java import java.rmi.Remote; import java.rmi.RemoteException; public interface FileInterface extends Remote { public byte[] downloadFile(String fileName) throws RemoteException; } 请注意FileInterface的以下特征: 它必须声明为public,这样客户机才能加载实现远程接口 的远程对象。 它必须扩展为Remote接口,以满足使该对象成为远程对象的 要求。 这个接口中的每种方法都必须投出一个java.rmi.RemoteException。 实现远程接口 下一步是实现接口FileInterface。实现的范例见代码范例2。 请注意,除了实现FileInterface之外,还把FileImpl 类扩展为UnicastRemoteObject。这表示FileImpl类 将用于创建一个单独的、不可复制的远程对象,它使用RMI缺省的基于TCP的传送 通道进行通讯。 代码范例2: FileImpl.java import java.io.*; import java.rmi.*; import java.rmi.server.UnicastRemoteObject; public class FileImpl extends UnicastRemoteObject implements FileInterface { private String name; public FileImpl(String s) throws RemoteException{ super(); name = s; } public byte[] downloadFile(String fileName){ try { File file = new File(fileName); byte buffer[] = new byte[(int)file.length()]; BufferedInputStream input = new BufferedInputStream(new FileInputStream(fileName)); input.read(buffer,0,buffer.length); input.close(); return(buffer); } catch(Exception e){ System.out.println("FileImpl: "+e.getMessage()); e.printStackTrace(); return(null); } } } 开发服务器 第三个步骤是开发服务器。服务器需要做三件事: 创建RMISecurityManager的一个实例并安装它 创建远程对象(在本例中是FileImpl)的一个实例 在RMI注册表中登记这个创建的对象。实现的范例见代码范例3。 代码范例 3: FileServer.java import java.io.*; import java.rmi.*; public class FileServer { public static void main(String argv[]) { if(System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } try { FileInterface fi = new FileImpl("FileServer"); Naming.rebind("//127.0.0.1/FileServer", fi); } catch(Exception e) { System.out.println("FileServer: "+e.getMessage()); e.printStackTrace(); } } } 语句Naming.rebind("//127.0.0.1/FileServer", fi)假定RMI 注册表在缺省的端口号1099上运行。但是,如果RMI注册表在其他端口号上运行, 就必须在这一句中指定端口号。例如,如果RMI注册表在端口4500上运行,那么 这一句就变成: Naming.rebind("//127.0.0.1:4500/FileServer", fi) 另外,在这里要着重指出,我们假定rmi注册表和服务器是在同一台电脑上运 行。如果不是这样,只需修改rebind方法中的地址即可。 开发客户机 下一步是开发客户机。客户机可以远程调用远程接口 (FileInterface)中指定的任何方法。但是为了能这么做,客户 机首先必须从RMI注册表中获得指向该远程对象的引用。获得引用之后就可以调 用downloadFile方法了。客户机的实现请见代码范例4。在这个实 现中,客户机从命令行接收两个参数: 第一个参数是要下载文件的名称,第二个参数是要下载的文件所在主机的地 址,也就是运行文件服务器的那台电脑的地址。 代码范例4: FileClient.java import java.io.*; import java.rmi.*; public class FileClient{ public static void main(String argv[]) { if(argv.length != 2) { System.out.println("Usage: java FileClient fileName machineName"); System.exit(0); } try { String name = "//" + argv[1] + "/FileServer"; FileInterface fi = (FileInterface) Naming.lookup(name); byte[] filedata = fi.downloadFile(argv[0]); File file = new File(argv[0]); BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(file.getName())); output.write(filedata,0,filedata.length); output.flush(); output.close(); } catch(Exception e) { System.err.println("FileServer exception: "+ e.getMessage()); e.printStackTrace(); } } } 运行应用程序 为了运行应用程序,我们需要生成存根和基干,编译服务器和客户机,启动 RMI注册表,最后是启动服务器和客户机。 为了生成存根和基干,请使用rmic编译器: prompt> rmic FileImpl 这将生成两个文件:FileImpl_Stub.class和 FileImpl_Skel.class。存根是一个客户机代理,基干是一个服 务器基干。 下一步是编译服务器和客户机。用javac编译器来做这件事。但是请注意:如 果服务器和客户机是在两台不同的机器上开发的,为了编译客户机,需要把接口 (FileInterface)复制一份。 最后,启动RMI注册表并运行服务器和客户机。为了在缺省的端口号上启动 RMI注册表,请在Windows中使用命令rmiregistry或 start rmiregistry。为了在其他端口号上启动RMI注册表,可以 提供该端口号作为RMI注册表的一个参数: prompt> rmiregistry portNumber 运行RMI注册表之后,就可以启动服务器FileServer了。但是, 因为在服务器应用程序中正在使用RMI安全管理员,所以需要一个安全方针来与之 相配。下面是一个安全方针范例: grant { permission java.security.AllPermission "", ""; }; 注意: 这只是一个方针的例子。它允许任何人做任何事情。对于关键 性事务应用程序,你需要指定更严格的安全方针。 现在,为了启动服务器,需要把除了客户机类 (FileClient.class)之外的所有类(包括存根和基干)复制一 份。请使用以下命令启动服务器,假定安全方针位于文件policy.txt中: prompt> java -Djava.security.policy=policy.txt FileServer 为了在另一台机器上启动客户机,需要复制远程接口 (FileInterface.class)和存根 (FileImpl_Stub.class)。请使用以下命令启动客户机: prompt> java FileClient fileName machineName 其中fileNamefileName是要下载的文件,machineName 是该文件所在的机器(运行文件服务器的那台机器)。如果一切顺利,那么客户 机就存在了,下载完的文件保存在本地的机器上。 <淘宝热门商品:
 

¥:48.00 

纤体·丽颜New Concept茶坊 纯天然美容瘦身品位花饮

超级瘦腿!(迷迭香柠檬马鞭草)袋泡瘦腿茶 1月量2盒 包快递哦!

 

3.50 元  

联达电子音响材料网淘宝分铺

【联达电子】镀银优质九脚电子管管座

来源:程序员网

小小豆叮

jsp处理表单的一些经验分享

之前一直写struts,在页面跳转和表单提交这一类问题上碰了不少钉子,于是想把处理这类问题的经历和见解写出来,供各位业内的同仁参考,有不对的地方,敬请斧正! 1:超连接跳转 我们在超连接的时候,常常连接到一个jsp或者Action,比如: XXX 这样做会有一个问题:在test.jsp中,除你传递的param1和param2参数外,你用request.getParamter()取任何原来页面的表单元素都会为空,这是因为这种方式会产生新的request生命周期,在这个request中只会包含超连接后跟随的?param1这种参数, 因此我的建议是如果不是很简单的页面跳转(比如回登陆页面之类的),尽量不要用这种超连接方式。 2:即传参又提交表单 如果确实既要像上述第一种方式传参数,又要提交表单的话,可以采取如下方式: XXX在脚本中如下处理: function commonSubmit(url) { form1.action="/jsp/managerAction.do?"+url; form1.submit(); } 提交到Action和jsp是一样的原理,但要记住 中method=post不能少,否则它只提交表单而不传param参数了(正好和第一种相反:) ) 3:js和java变量互传 在jsp中经常会遇到把js变量赋给java变量,或者将java变量赋给js变量的情况,在此将通用的处理方法小结如下: java变量传给js好办,var a ="";注意要将引号""加上;js变量给java稍微复杂点,一般是在表单中用一个 的隐藏表单元素,然后在脚本中将js变量值赋给它: var jsParamValue=aaaa; form1.jsParam.value=jsParamValue; 然后就可以request.getPrameter("jsPrama");来取得js变量值了 4:Action中request不会丢掉 不知大家有没有注意到这个好处,Struts架构中是由一个ActionServlet来作为MVC的控制器角色,jsp页面提交后request是传到ActionServelt中的, 而ActionServlet将根据struts-config.xml中的配置调用相应的Action的方法,并将从jsp中获得的request传给Action类,这样request的生命周期是连续的,即你在jsp中提交了表单,在Action中执行了方法,再回到jsp页面,用request.getParamter()取jsp页面的表单元素值会发现它还在,这对于页面下拉列表等选择项防止复位是一个很好实现方法。 5:传参时参数有空格的情况 如果你提交form时带参数,比如form1.action="/jsp/Action.do?param1="+value1,注意如果value1中带有空格的话,你在 Action中request.getParameter("param1"); 取得的只是空格前的值,因此如果有这种带空格的参数在传递时,个人建议是将其转化为特定的字符串,value1=value1.replaceAll(" ","%NULL%"); 然后在Action中将其转回来:request.getParamter("param1").replaceAll("%NULL%"," "); 6:form-data属性 如果你要用来上传文件的话,注意在一个表单中如果有enctype="multipart/form-data"属性的话,是不能接收除type=file外的其他表单元素类型的。 即如果你把和放在同一表单中,而该表单有enctype="multipart/form-data"的话,request.getParamter取text的值会为空, 这个问题的最简单的解决方法是将单独放一个表单,上传文件时只提交该表单即可。 7:jsp中开模式对话框的方式 与Swing中类似,jsp中也有模式对话框这一概念,你可以将一个jsp页面放到一个模式对话框中打开,这样在模式对话框消失前,原jsp页面将不可操作。特别适合父页面中要做一些额外的选择操作,而又没必要跳转到新的jsp页面的时候, 开模式对话框的方式参考如下: Function open() { If(window.showModelDialog()) { Var returnValue = showModelDialog(“/jsp/模式窗口包含的jsp页面路径”; help=0;status=0;center=yes;dialogWidth=100pt;dialogHeight=100pt”); } } <淘宝热门商品:
 

35.00 元 

【天使名妆】100%纯棉休闲瑜珈裤

 

¥:8.80 

『五博』新奥尔良烤鸡腌料

来源:程序员网

小小豆叮

Java语言中常见的十大误解

JAVA 语 言 自 从 应 用 于 Internet, 迅 速 成 为 全 球 热 点。 它 的 平 台 无 关 性 仿 佛 成 为 解 决 互 易 操 作 性 和 可 移 植 性 的 灵 丹 妙 药。 然 而 对 于 JAVA 语 言 的 认 识 仍 有 不 少 误 解。 1.JAVA 是 HTML 的 扩 充 JAVA 是 一 个 编 程 语 言, HTML 是 一 个 页 面 描 述 语 言。 除 了 新 版 本 HTML 可 以 在 WEB 页 中 插 入 JA-VA 小 应 用 外, 它 们 之 间 没 有 任 何 相 同 之 处。 2.JAVA 是 一 种 很 容 易 学 会 的 编 程 语 言 没 有 一 种 和 JAVA 同 样 有 力 的 语 言 是 简 单 的。 当 它 写 演 示 小 程 序 时, 非 常 容 易; 但 当 它 真 正 做 一 些 重 要 的 工 作 时, 却 很 费 力。 JAVA 库 有 150 多 种 类 和 接 口, 虽 然 对 许 多 程 序 用 户 不 需 要 整 个 类 库, 但 每 个 项 目 都 需 要 类。 3.JAVA 是 一 个 简 单 的 编 程 环 境 一 些 人 喜 欢 只 用 vi 编 辑 器 和 dbx 调 试 器 来 写 程 序。 但 是 PC 和 MAC 编 程 者 已 习 惯 用 类 似 VB 风 格 的 拖 拉 式 表 格 设 计 工 具 或 集 成 开 发 环 境, 这 对 他 们 来 说 是 一 团 麻。 但 是, 一 旦 类 似 于 Syman-tec 公 司 的 Cafe 工 具 或 Borland 公 司 的 Latte 工 具 问 世, JAVA 的 开 发 时 间 就 会 大 幅 度 减 少。 4.JAVA 将 成 为 所 有 平 台 的 统 一 编 程 语 言 在 理 论 上, 这 是 可 能 的。 但 这 并 不 是 说 用 户 就 已 得 到 应 用 开 发 的 最 方 便 途 径。 JAVA 应 用 的 开 发 并 不 像 (可 能 永 远 不 像) 用 MFC 或 VB 开 发 的 Windows 应 用 那 样 好, 而 且 JAVA 提 供 的 图 形 开 发 工 具 功 能 也 太 简 单。 我 们 希 望 JAVA 类 库 很 快 变 丰 富。 5.JAVA 是 解 释 型 的, 它 对 于 特 殊 平 台 的 重 要 应 用 太 慢 了 许 多 编 程 者 在 类 似 于 用 户 界 面 方 面 花 了 太 多 的 时 间。 所 有 程 序, 无 论 用 什 么 语 言 编 写, 都 会 有 足 够 的 时 间 对 鼠 标 进 行 检 测。 当 然, 目 前 我 们 尚 未 用 当 前 的 JAVA 版 本 来 做 CPU 密 集 的 任 务。 但 是, 开 发 一 个 将 JAVA 中 间 码 转 换 成 本 地 码 的 编 译 器 是 非 常 容 易 的。 6. 所 有 的 JAVA 程 序 都 在 WEB 页 中 运 行 所 有 的 JAVA 小 程 序 (applet) 都 在 WEB 页 中 运 行。 在 浏 览 器 中 运 行 的 JAVA 程 序, 这 是 applet 的 定 义。 但 编 写 不 依 赖 于 WEB 浏 览 器 运 行 的 JAVA 程 序 是 可 能 的, 也 是 非 常 有 用 的。 这 些 程 序 完 全 可 以 移 植, 而 且 因 为 JAVA 比 C++ 更 方 便、 出 错 更 少, 它 是 编 程 的 一 个 很 好 的 选 择, 也 是 学 习 编 程 的 首 选 入 门 语 言。 一 旦 它 和 界 面 工 具 以 及 数 据 库 存 取 工 具 结 合, 将 更 有 竞 争 力。 7.JAVA 消 除 了 CGI 编 程 的 需 要 绝 对 不。 在 今 天 的 技 术 下, CGI 仍 是 ap-plet 和 服 务 器 之 间 最 方 便 的 通 讯 手 段。 服 务 器 仍 将 需 要 CGI 语 言 来 处 理 applet 发 送 的 信 息。 当 然, 用 户 可 以 用 JAVA 语 言 来 写 CGI, 如 同 Perl 或 C 那 样 简 单。 8.JAVA 将 彻 底 改 变 客 户 / 服 务 器 计 算 这 是 可 能 的。 SUN 公 司 已 公 布 了 各 种 数 据 库 类 库 的 计 划, 这 将 使 得 用 JAVA 开 发 客 户 / 服 务 器 应 用 和 用 JAVA 的 网 络 类 库 开 发 网 络 程 序 一 样 简 单。 9. 使 用 JAVA, 用 户 可 以 用 500 美 元 的 In ┐ ternet 设 备 来 代 替 现 在 的 计 算 机 这 种 认 为 人 们 会 放 弃 功 能 丰 富、 使 用 方 便 的 台 式 机 来 追 求 没 有 外 存 且 功 能 有 限 的 机 器, 是 完 全 不 合 理 的。 但 是 Internet 设 备 可 以 作 为 台 式 机 的 便 携 式 助 手。 如 果 价 格 合 理, 用 户 当 然 愿 意 用 一 台 Internet 浏 览 器 在 用 餐 时 自 由 地 选 择 阅 读 新 闻。 这 就 是 JAVA 的 魅 力。 10.JAVA 将 允 许 放 弃 基 于 部 件 的 计 算 模 式 当 人 们 谈 到 部 件, 有 许 多 不 同 的 含 义。 就 可 视 控 制 (Visual Control), 例 如 能 插 入 GUI 程 序 的 OCX 部 件, JAVA 还 没 有 设 定 一 个 标 准。 就 使 用 CORBA 接 口 及 OpenDoc 和 分 布 计 算 模 型 进 行 合 作 的 能 力, 这 不 久 就 将 开 始。 目 前 网 上 已 有 CORBA 接 口 的 测 试 版。 <淘宝热门商品:
 

 

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

 

100.00 元 

韩国手表正品intercrew品牌手表LED手表

来源:程序员网

小小豆叮

java语言的网络功能与编程

Java语言是Internet上最热门的编程语言,本文针对Java的网络功能,对Java从网络上获取图象、声音、HTML文档及文本文件等编程方法作了初步的介绍,同时介绍了动态获取网络上资源的方法作了介绍。文中提供了大量简明易懂的实例。 关键词:Java;Internet;网络 Java语言是Internet上新兴的编程语言,对Java的特性以及基本的编程方法已有很多文章作过介绍。但是,广大Java爱好者更希望了解Java更深一步的编程方法,本文就Java的网络功能及其编程方法 作一初步的介绍。 为了方便初次接触Java的读者,本文先就Java编程的一些常识作简单介绍。 一、Java编程简介 1. 编程环境: 对于大部分读者,以下的配置是较为经济的一种选择: 操作系统 Win95 编译软件 JDK1.01 浏览软件 Netscape2.0以上(32位) 2. 编程方法: 先用文本编辑器如Edit、NotePad等输入Java程序,以.java为文件名后缀存盘。 再执行命令行:“Javac 文件名”来编译Java程序。编译后生成后缀为.class的字节码文件。 最后,如果是Java Applitcation,则执行命令行:“Java 字节码文件名”来运行Java程序。 如果是Java Applet,则用文本编辑器输入调用该Java Applet的HTML 文档, 以 .htm 为文件名后缀存盘。 再执行命令行:“appletviewer HTML文件名”来运行Java Applet。或用Netscape打开该HTML文档。 3. 关于本文中程序的说明 为了使程序能够最简洁地体现其所代表的编程方法,本文中的程序一般采用最简单的形式,省略了线程等内容。因此,本文的程序不是“好”的程序,但最容易为初学者理解。 本文的所有程序经编译后,生成的字节码文件及对应的HTML文档已上载到http://www.shu.edu.cn/~xyx/test/jvnet, 均可正确运行。连入Internet的读者可用浏览器打开该地址,查看运行效果。 连入Internet的读者也可以在本地硬盘输入并编译本文的程序,用Netscape的File/Open File菜单打开HTML文档,体会编程方法并查看运行效果。如果读者想将Java Applet 放到自己的主机上或其他ftp服务器上,在Netscape中用http协议或ftp协议调用,出于安全性限制,应作如下修改: 如果读者在某个WWW主机上有帐号,可以做个人Homepage(一般在用户根目录创建WWW或public_html目录即可,Homepage的地址为http://HostName/~个人帐号),可将本文程序中对应的http://www.shu.edu.cn/~xyx/部分修改为读者自己的Web结点地址,然后将编译后生成的字节码文件及对应的HTML文档上载到自己的结点上。 如果读者的计算机连入了Internet,也可以找一个可以上载的ftp结点,如:ftp://ftp.shnet.edu.cn/incoming,将本文程序中对应的http://www.shu.edu.cn/~xyx/部分修改为ftp结点的地址,将编译后生成的字节码文件及对应的HTML文档上载到该结点上,以查看运行效果。 如果读者的计算机没有联网,也可以在单机上运行Web 服务软件如Webstar for Win95,将本文程序中对应的http: //www. shu.edu.cn/~xyx/部分修改为“http://本地IP地址”的形式,来模拟网络编程。 二、Java网络功能及获取网络上资源的一般步骤 Java程序可以获取网络上结点的图象、声音、HTML文档及文本等资源,并可以对获得的资源进行处理。例如Java程序可以每隔一定时间读取某结点提供的最新数据,并以图表的形式显示出来。 在编程处理上,一般先生成一个URL类型的对象,然后用 Java中相应的方法(method)获取该对象所代表的资源。下面分别介绍Java网络功能的几个例子,并由此介绍几种不同的编程方法。 三、从网络上获取图象 Java Applet可以直接从网络上结点获取图象并显示出来。 为了了解其编程方法和从本地显示图象的编程有何不同,我们先不考虑网络功能,来看一个简单的图象显示的例子: ●程序1 import java.applet.*; import java.awt.*; public class imag0 extends Applet{ Image image; public void init() { image=getImage(getDocumentBase(),"test.gif"); } public void paint(Graphics g) { g.drawImage(image, 0, 0,this); } } 这是一个最简单的获取并显示图象的例子, 在该例中, 先用getImage(getDocumentBase(),图象文件名)从HTML文档所在位置调用图象test.gif,并由此生成一个Image类型的对象image, 然后用drawImage(image, 0, 0,this)在屏幕上将图象显示出来。 如果想从网络上其他结点获取图象,关键是创建对应于网络上其他结点的Image类型的对象,一旦获得Image类型的对象获得了,便可以对其进行任何可能的图象操作。 Java提供了如下方法可以创建对应于其他结点的图象: getImage(new URL(字符串)) 其使用格式可有两种: String url = "结点URL"; Image image; try { image = getImage(new URL(url)); } catch(Exception e){ System.out.println("Can´t open the URL "); } 或 URL imgur=null; Image image; try { imgur=new URL("结点URL "); } catch (MalformedURLException e) { System.out.println("Can´t open the URL "); } image=getImage(imgur); 前一种格式用“new URL(url)”生成 URL 对象, 并直接作为getImage的参数,后一种格式先用“new URL(url)”生成一个 URL对象,再传给getImage。两种格式本质上是一样的。两种格式中,生成URL对象的部分都包含在 try{ 获取URL对象 } catch (MalformedURLException e) { 出错提示 } 中。 例如要调用http://www.shu.edu.cn/~xyx/img/shnet.jpg结点的图象,第一种格式完整的程序如下: ●程序2 import java.applet.*; import java.net.*; import java.awt.*; public class imag extends Applet{ Image image; public void init() { String url = "http://www.shu.edu.cn/~xyx/img/shnet.jpg"; try { image = getImage(new URL(url)); } catch(Exception e){} } public void paint(Graphics g) { g.drawImage(image, 0, 0,this); } } 第二种格式完整的程序如下: ●程序3 import java.applet.*; import java.net.*; import java.awt.*; public class imag2 extends Applet{ Image image; URL imgur=null; public void init() { try { imgur=new URL("http://www.shu.edu.cn/~xyx/img/shnet.jpg"); } catch (MalformedURLException e) { System.out.println("Can´t open the URL "); } image=getImage(imgur); } public void paint(Graphics g) { g.drawImage(image, 0, 0,this); } } 将上述两个程序分别以imag.java和imag2. java 存盘, 执行javac imag.java和javac imag2.java,将得到编译后生成的imag.class和imag2.class,最后创建调用这两个Java Applet的HTML文档,如imag.class对应的HTML文档可如下: < html > < head > < title >Example < /title > < /head > < center > < applet code=imag.class width=550 height=250 > < /applet > < /html > 将该HTML文档存入test.html文件,用Netscape打开, 如果你的计算机连入了Internet,便可以看到Java Applet 所显示的从网络上获得的图象了。(对于本文中其他不同的Java Applet, 对应的HTML文档只要修改其中相应的“code=imag.class”即可。) 四、从网络上获取声音 Java从网络上获取声音文件并播放声音的编程方法有两类,一是利用Java提供的play(URL)及play(URL,String) 直接播放网络上的声音文件,另一类是通过getAudioClip(URL)或getAudioClip(URL,String)先从网络上获取声音文件,并生成AudioClip 类型的对象,然后对该对象进行操作。 前者的使用格式是: String Audur = "结点URL"; try { play(new URL(Audur)); } catch(Exception e){} 或 String Audur = "结点URL"; try { play(new URL(Audur),声音文件名); } catch(Exception e){} 后者使用的格式是: String Audur = "结点URL"; AudioClip loopClip; try { loopClip = getAudioClip(new URL(Audur)); } catch(Exception e){ System.out.println("Can´t open the URL "); } 或 String Audur = "结点URL"; AudioClip loopClip; try { loopClip = getAudioClip(new URL(Audur) ,声音文件名); } catch(Exception e){ System.out.println("Can´t open the URL "); } 上面的四种格式都是将生成URL对象部分--“new URL(url)”直接作为play或getAudioClip的参数;和前面处理图象的例子一样,也可以先用“new URL(url)”获取一个URL对象, 再传给 play 或getAudioClip。如对第一种play(URL)的格式, 也可采用如下的编程格式: URL Audur =null; try { Audur=new URL("结点URL "); } catch(Exception e){ System.out.println("Can´t open the URL "); } play(Audur); 下面对前述四种从网络上获取并播放声音文件的格式各举一简单的例子, 以作编程时参考: ●程序4 格式一 import java.applet.*; import java.awt.*; import java.net.*; public class sound1 extends Applet { AudioClip loopClip; public void paint(Graphics g) { String Audur = "http://www.shu.edu.cn/~xyx/java/Animator/audio/bark.au"; try { play(new URL(Audur)); } catch(Exception e){} } } ●程序5 格式二 import java.applet.*; import java.awt.*; import java.net.*; public class sound2 extends Applet { AudioClip loopClip; public void paint(Graphics g) { String Audur = "http://www.shu.edu.cn/~xyx/java/Animator/audio/"; try { play(new URL(Audur),"bark.au"); } catch(Exception e){} } } ●程序6 格式三 import java.applet.*; import java.awt.*; import java.net.*; public class sound extends Applet{ AudioClip loopClip; public void init() { String Audur = "http://www.shu.edu.cn/~xyx/java/Animator/audio/bark.au"; try { loopClip = getAudioClip(new URL(Audur)); } catch(Exception e){} } public void paint(Graphics g){ loopClip.loop(); } } ●程序7 格式四 import java.applet.*; import java.awt.*; import java.net.*; public class sound0 extends Applet{ AudioClip loopClip; URL auur; public void init() { try { auur=new URL("http://www.shu.edu.cn/~xyx/java/Animator/audio/"); } catch (MalformedURLException e) { System.out.println("Can´t open the URL "); } loopClip = getAudioClip(auur,"bark.au"); } public void paint(Graphics g){ loopClip.loop(); } } 五、显示网络上其他HTML文档 利用Java提供的getAppletContext().showDocument(URL)可以显示其他结点的HTML文档,同前面的显示网络上其他结点的图象,有两种格式,下面各举一例: ●程序8 格式一 import java.applet.*; import java.awt.*; import java.net.*; public class showdoc extends Applet { URL docur= null; public void paint(Graphics g) { try { docur=new URL("http://www.shu.edu.cn/~xyx/doc/manhua.html"); } catch (MalformedURLException e) { System.out.println("Can´t open the URL "); } if (docur != null) { getAppletContext().showDocument(docur,"_blank"); } } } ●程序9 格式二 import java.applet.*; import java.awt.*; import java.net.*; public class showdoc2 extends Applet { URL docur= null; public void paint(Graphics g) { try { getAppletContext().showDocument(new URL("http://www.shu.edu.cn/ ~xyx/doc/manhua.html")); } catch (MalformedURLException e) { System.out.println("Can´t open the URL "); } } } 六、读取网络上文件内容 前述的网络功能只是显示或播放网络上结点的图象、 声音及HTML文档,并没有对其内容进行处理。事实上,Java还可读取网络上文件的内容,并对其内容进行处理。 读取网络上文件内容的步骤可如下: 1. 创建一个URL类型的对象 如: String url = "ftp://202.120.127.218/incoming/test/readtxt.html"; URL fileur; try { fileur = new URL(url); } catch ( MalformedURLException e) { System.out.println("Can´t get URL: " ); } 2. 利用URL类的openStream(),获得对应的InputStream类的对象 如:InputStream filecon = fileur.openStream(); 3. 将InputStream对象转化为DataInputStream类的对象 如:DataInputStream filedata = new DataInputStream(filecon); 4. 读取内容 如对前面的filedata,可用filedata.readLine() 一行一行读取内容,或用filedata.readchar一个字符一个字符读取内容。 对读取到的内容,可由Java Applet进行各种处理, 并将处理结果用各种方式显示出来。 下面的例子是读取 http://www.shu.edu.cn/~xyx/doc/manhua.html文件内容的例子,为简洁起见,该例中只将文件的内容逐行读出,并在文本区显示出来。 ●程序10 import java.io.*; import java.net.*; import java.awt.*; import java.applet.*; public class showfile extends Applet{ URL fileur; TextArea showarea = new TextArea("Please wait a while for get text",10,70); public void init() { String url = "http://www.shu.edu.cn/~xyx/doc/manhua.html"; try { fileur = new URL(url); } catch ( MalformedURLException e) { System.out.println("Can´t get URL: " ); } add(showarea); } public void paint(Graphics g) { InputStream filecon = null; DataInputStream filedata = null; String fileline; try { filecon = fileur.openStream(); filedata = new DataInputStream(filecon); while ((fileline = filedata.readLine()) != null) { showarea.appendText(fileline+" "); } } catch (IOException e) { System.out.println("Error in I/O:" + e.getMessage()); } } } 七、动态使用网络上资源 在前面介绍的例子的基础上,可以动态地利用网络上的资源。其方法是编制一个线程,每隔一定时间自动到相应结点读取最新的内容。本文对线程的编制不再展开,读者可参考有关文章或直接套用下面的例子。 例如对上例中读取http://www.shu.edu.cn/~xyx/doc/manhua.html文件内容的例子,加入线程后如下所示。该例子每隔5秒更新一次数据。如果http://www.shu.edu.cn/~xyx/doc/manhua.html中存放的是一些变化较快的信息如股市行情等,并有程序随时动态地更新其内容,则在Web中加入这种Java Applet,可以让流览者得到动态的信息。进一步,也可以在程序中对数据进行处理,并用图形方式显示处理结果。例如将各时刻的数据绘制成曲线,流览者可以看到动态变化的曲线。 //程序11 import java.io.*; import java.net.*; import java.awt.*; import java.applet.*; public class dynashow extends java.applet.Applet implements Runnable { Thread dthread; URL fileur; TextArea showarea = new TextArea("Wait for a while...",10,70); public void init() { String url = " http://www.shu.edu.cn/~xyx/doc/manhua.html "; try { fileur = new URL(url); } catch ( MalformedURLException e) { System.out.println("Can´t get URL: " ); } add(showarea); } public void start() { if (dthread == null) { dthread = new Thread(this); dthread.start(); } } public void stop() { if (dthread != null) { dthread.stop(); dthread = null; } } public void run() { InputStream filecon = null; DataInputStream filedata = null; String fileline; while(true){ try { filecon = fileur.openStream(); filedata = new DataInputStream(filecon); while ((fileline = filedata.readLine()) != null) { showarea.appendText(fileline+" "); } } catch (IOException e) { System.out.println("Error in I/O:" + e.getMessage()); } try{ dthread.sleep(5000); } catch (InterruptedException e){} repaint(); } } } 八、Java网络能力的限制 出于安全性考虑,在用netscape浏览时,Java Applet 只能和其所在的主机建立连接,因此,前面的程序编译后大部分只能存放在http://www.shu.edu.cn/~xyx对应的主机上。存放到其他主机时需更改程序中的结点地址。否则浏览器将显示安全出错。 但对显示网络上其他HTML文档没有此限制(如程序8、9),读者可以将程序编译后放到任意WWW服务器或FTP服务器,均可正常运行。 此外,当浏览器从本地盘打开调用Java Applet的HTML文档时,也不受此限制。因此,本文所有的程序都可存放在本地盘编译,只要用netscape的File/Open File菜单打开,便可正确运行。 对于另一种Java程序--Java Application,也无此限制,例如对于读取网络上文件内容的程序10,对应的Java Application可作如下编程: ●程序11 import java.io.*; import java.net.*; import java.awt.*; class showfile2 { public static void main(String args[]){ InputStream filecon = null; DataInputStream filedata = null; String fileline; String url = "http://www.shu.edu.cn/~xyx/doc/manhua.html"; URL fileur; try { fileur = new URL(url); filecon = fileur.openStream(); filedata = new DataInputStream(filecon); while ((fileline = filedata.readLine()) != null) { System.out.println(fileline+" "); } } catch (IOException e) { System.out.println("Error in I/O:" + e.getMessage()); } } } 将其以showfile2.java存盘,用javac showfile2.java编译后,只需执行“java showfile2”便可以在屏幕上打印出http://www.shu.edu.cn/~xyx/doc/manhua.html 文件的内容。 九、创建URL对象的方法 在前面的例子中我们统一使用new URL(url字符串)的形式创建URL对象。其实,Java提供了四种创建URL对象的形式: 1.new URL(url字符串) 本文中的程序均采用此种格式,如: new URL("http://www.shu.edu.cn/~xyx/doc/manhua.html") 2.new URL(协议,主机名,文件名或路径) 如程序2中的 String url = "http://www.shu.edu.cn/~xyx/img/shnet.jpg"; image = getImage(new URL(url));部分可改为: image = getImage(new URL("http","www.shu.edu.cn","/~xyx /img/shnet.jpg")); 3.new URL(协议,主机名,端口号,文件名或路径)1 如:new URL("http","www.shu.edu.cn",80, "/~xyx/doc/manhua.html") 4.new URL(基准url,文件名或路径) 十、实现网络功能的其他方法 以上着重介绍了利用Java的URL类实现从网络上获取声音、 图象、HTML文档及文件数据的编程方法。Java的网络功能很强大,除上面介绍的外,还可以利用URLconnection 类实现更广泛的网络功能,如向WWW 服务器上的 CGI 程序发送信息等; 通过 Socket 及ServerSocket类,可以自己编写客户软件及服务软件,并可以自己设计通讯协议。 <淘宝热门商品:
 

68.00元  

海洋新奇特购物天堂

 

¥:78.00 

皇冠舒友阁 顶级特效美容护肤 效果才是硬道理

皇冠热销 印疤修复液 消除深浅痘印等色印、有效改善凹凸疤痕

来源:程序员网

小小豆叮

关于applet写入文件的处理

众所都知见于安全性考虑,applet在ie、netscape中没有写入文件的能力,包括本地、服务器文件。那么我们怎样才能实现一些数据的保留呢?(象本程序代码中记录积分的功能)。 一个方法是通过服务器端的servlet写入文件,applet端的代码如下: private void Send(){ message=score+"#"+tf.getText (); showStatus("Message send"); String queryString="/servlet/javaduke.servlet.SaveServlet?message="+ URLEncoder.encode(message); p("Attempting to send:"+message); try{ connect=(new URL(chatURL,queryString)).openConnection(); showStatus("打开连接"); showStatus(connect.toString ()); System.out.println("open connection"); connect.setDefaultUseCaches(false); connect.setUseCaches (false); connect.setDoInput (true); connect.setDoOutput(false); System.out.println("dooutput false"); connect.connect(); System.out.println("open stream"); p("Made connection to"+connect); showStatus("试图连接、读取回应"); InputStreamReader reader=new InputStreamReader(connect.getInputStream ()); BufferedReader in=new BufferedReader(reader); message=in.readLine (); while(message!=null){ tf.setText(message); message=in.readLine (); } showStatus("对话成功"); } catch(MalformedURLException e2){ System.err.println ("MalformedURLException!"); e2.printStackTrace (System.err ); showStatus("MalformedURLException"); } catch(IOException e1){ System.err.println ("IOException"); e1.printStackTrace (System.err); showStatus(e1.toString ()); } } server端代码如下! Servlet写入文件(www.mycgiserver.com调试成功) import javax.servlet.http.*; import java.io.*; import java.util.*; public class SaveServlet extends HttpServlet { String counter,counter2; //Initialize global variables public void init(ServletConfig config) throws ServletException { super.init(config); } //Service the request public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { File file=new File("/members/YourID/servlet/gamelog.txt"); RandomAccessFile raf; if(!file.exists()){ raf=new RandomAccessFile(file,"rw"); counter="210#javaduke "; raf.seek(0); raf.writeBytes(counter); raf.close(); } else{ counter=request.getParameter("message"); raf=new RandomAccessFile(file,"rw"); raf.seek(0); raf.writeBytes(counter); raf.close(); } response.setContentType("text/html"); PrintWriter out = new PrintWriter (response.getOutputStream()); out.print("Saved OK!"); out.close(); } //Get Servlet information public String getServletInfo() { return "game.SaveServlet Information"; } } <淘宝热门商品:
 

¥:59.00 

冉冉天使屋-外贸童装批发代理

冬季宝宝必备 加厚小老虎造型棉哈衣/可当包被 土黄色(0-1岁)

 

225.00 元  

上海商盟】易淘视听商城

五钻100%原装松下HTX7耳机经典白色 松下头戴式耳机 东方神起代言

来源:程序员网

小小豆叮

Java语言灵巧指针与垃圾回收

在JAVA 和 C# 中都有垃圾回收功能,程序员在分配一段内存后可以不再理会,而由垃圾回收自动回收,从而使程序员从复杂的内存管理中解脱出来。这是JAVA 和 C#的一大优点。而C++程序员在用 new 分配了一段内存后,还必须用 delete 释放,否则将造成资源泄漏。因此,一些C++ 书上经常告诫程序员:要养成好的习惯,new 与 delete 要成对出现,时刻记住将内存释放回系统。但是,事情只是这么简单吗? 经常地,在使用C++的过程中,我们会遇到下面的情形: class A { public: A(); ~A(); SetNextPtr(A* Ptr) {pNext=Ptr;} private: A * pNext; } 一般地,为了不引起内存泄漏,我们会在析构函数中释放pNext,象下面这样: A::~A() { if(pNext) delete pNext; pNext=NULL; } 对于一般情况,这样就够了,但在某些情形下,这样也会出问题的,象下面这样: A *ptrB = new A;; A *ptrA = new A; ptrB->SetNextPtr(ptrA); ptrA->SetNextPtr(ptrB); delete ptrB; 这样会出问题,因为这些指针连成了一个回环,无论从那一个点开始删除,都会造成一个指针被删除两次以上,这将使得程序抛出异常。当然,也有一些方法可以用来解决这个问题,但是我要说明的是:对于C++程序员来说,养成一个好的习惯并不难,难就难在有时候这样将把你带入一种逻辑的混乱当中 ,增加一些不必要的麻烦,有时甚至不知所措。 可是如何解决这个问题呢?如果C++也具有垃圾回收的功能,那么,这个问题当然就迎刃而解了。但是C++属于编译型语言,不会具备这个功能。长期以来,我也一直在思考这个问题,想找出一种方法来使自己从这种麻烦中解脱出来。直到最近开始学习泛型编程,看到灵巧指针的介绍以后,我灵光一闪,终于找到了办法来解决这个问题。 大家知道,灵巧指针具有一些灵巧特性,如在构造时可以自动初始化,析构时可以自动释放所指的指针。我们就利用它的这些特性来实现我们的垃圾回收。 首先,我们要想办法来对我们用 new 分配的每一段内存增加引用记数,即记录下当前指向它的灵巧指针个数,当最后一个指向它的指针被释放时,我们就可以释放这段内存了。由此,我们进行了new 和 delete 的全局重载,并引入了CPtrManager 类。 void operator delete(void * p) { int mark=thePtrManager.GetMarkFromPtr(p); if(mark>0) thePtrManager.UserDelete(mark); free(p); } void * operator new(size_t size) { return thePtrManager.MallocPtr(size); } class CPtrManager { public: int GetCount(int mark,void * p); file://得到当前的引用记数 static CPtrManager* GetPtrManager(); file://得到全局唯一的CPtrManager 指针 void UserDelete(int mark); file://删除 mark 标志的指针,并对指针和标志复位 void * MallocPtr(size_t size); file://new()调用它分配内存; BOOL AddCount(int mark,void * Ptr); file://增加引用记数 BOOL Release(int mark,void * Ptr); file://减少引用记数 int GetMarkFromPtr(void * Ptr); file://通过指针得到标志 CPtrManager(); virtual ~CPtrManager(); private: static CPtrManager * p_this; file://指向全局唯一的CPtrManager 指针 void AddPtr(void * Ptr); file://增加一个新分配的内存 CPtrArray m_ptr; file://存放分配的指针的可变数组 CUIntArray m_count; file://存放指针的引用记数 void* pCurrent; file://最近刚分配的指针 unsigned int m_mark; file://最近刚分配的指针的标志 CUIntArray m_removed;//存放m_ptr中指针被删除后所空留的位置 }; 顾名思义,CPtrManager 就是用来管理指针的,对于我们用new 分配的每一个指针,都存放在m_ptr[index]中,并在m_count[index]中存放它的引用记数。同时,我们对每一个指针都增加了一个标志(mark >0,<=0为无效),这个标志同时存在于灵巧指针中(后面将看到),这是为了一种双重保险,并且在这里,这个标志就等于指针在m_ptr中的索引,这也为快速查找提供了方便。 总的思路是这样的:当我们用new分配一个指针时,这个指针将被存入CPtrManager中,当一个灵巧指针开始拥有这个指针时,CPtrManager将负责对这个指针的引用记数加 1 ,反之亦然,即一个灵巧指针开始释放该指针的拥有权时,CPtrManager将负责对这个指针的引用记数减 1 ,如果引用记数为 0 ,那么这个灵巧指针将负责对该指针 delete。 下面是灵巧指针的部分介绍: template class auto_ptr { public: auto_ptr() {mark=0;pointee=0;} auto_ptr(auto_ptr&rhs); auto_ptr(T*ptr); ~auto_ptr(){Remove();} T*operator->() const; operator T*(); T&operator*()const; auto_ptr&operator=(auto_ptr&rhs); auto_ptr&operator=(T*ptr); private: void Remove(); file://释放所指指针的拥有权 T*pointee; file://所拥有的指针 int mark;//所拥有的指针的标志 }; template void auto_ptr< T>::Remove() { CPtrManager * pMana=CPtrManager::GetPtrManager(); if(pointee&&pMana) { if(pMana->Release(mark,pointee)) file://减少引用记数 { if(pMana->GetCount(mark,pointee) ==0) delete pointee; file://如果引用记数为0,delete 指针 } else file://所拥有的指针不在CPtrManager 中,有可能在栈中 { file://User decide to do } } pointee=NULL; file://复位 mark=0; } template auto_ptr< T>::auto_ptr(auto_ptr&rhs) { pointee=rhs.pointee; mark=rhs.mark; CPtrManager * pMana=CPtrManager::GetPtrManager(); if(pMana) pMana->AddCount(mark,pointee); file://增加引用记数 } template auto_ptr< T>::auto_ptr(T*ptr) { mark=0; pointee=ptr; CPtrManager * pMana=CPtrManager::GetPtrManager(); if(pMana) { mark=pMana->GetMarkFromPtr(ptr); file://得到指针的标志 if(mark>0) pMana->AddCount(mark,pointee); file://如果标志不为0,增加引用记数 } } templateauto_ptr& auto_ptr< T>::operator=(auto_ptr&rhs) { if(pointee!=rhs.pointee) { Remove(); file://释放当前指针的拥有权 pointee=rhs.pointee; mark=rhs.mark; CPtrManager * pMana=CPtrManager::GetPtrManager(); if(pMana) pMana->AddCount(mark,pointee); } return *this; } template auto_ptr&auto_ptr< T>::operator = (T* ptr) { if(pointee!=ptr) { Remove(); pointee=ptr; CPtrManager * pMana=CPtrManager::GetPtrManager(); if(pMana) { mark=pMana->GetMarkFromPtr(ptr); if(mark>0) pMana->AddCount(mark,pointee); } } } 当到了这里时,我便以为大功告成,忍不住摸拳搽掌,很想试一试。结果发现对于一般的情况,效果确实不错,达到了垃圾回收的效果。如下面的应用: auto_ptr p1=new test; auto_ptrp2 = p1; auto_ptrp3 = new test; 但是,很快地,我在测试前面提到的回环时,就发现了问题,我是这样测试的: class test { auto_ptr p; }; auto_ptr p1=new test; auto_ptrp2 =new test; p1->p=p2; p2->p=p1; 当程序执行离开作用域后,这两块内存并没有象我想象的那样被释放,而是一直保留在堆中,直到程序结束。我仔细分析造成这种现象的原因,发现了一个非常有趣的问题,我把它称之为互锁现象。 上面p1 所拥有的指针被两个灵巧指针所拥有,除p1外,还有p2所拥有的 test 类中的灵巧指针p,p2亦然。也就是说,这两块内存的指针的引用记数都为 2 。当程序执行离开作用域后,p1,p2被析构,使它们的引用记数都为1,此后再没有灵巧指针被析构而使它们的引用记数变为 0 ,因此它们将长期保留在堆中。这就象两个被锁住的箱子,其中每个箱子中都装着对方的钥匙,但却无法把彼此打开,这就是互锁现象。 可是如何解决呢?看来必须对它进行改进。同时,我也发现上面的方法不支持多线程。所以,我们改进后的方法不仅要解决互锁现象,而且还要支持多线程。下面是我改进后的方法: 首先是如何发现这种互锁现象。我们知道,互锁现象产生的根源在于拥有堆中内存的灵巧指针本身也存在于已分配的堆内存中,那么,如何发现灵巧指针是存在于堆中还是栈中就成了问题的关键。由此,我引入了一个新的类 CPtr,由它来管理用 new 分配的指针,而 CPtrManager 专门用来管理 CPtr。如下所示: class CPtr { friend class CMark; public: int GetPtrSize(); file://得到用 new 分配指针的内存的大小 CMutex * GetCMutex(); file://用于线程同步 void * GetPtr(); file://得到用 new 分配的指针 CPtr(); virtual ~CPtr(); int GetCount(); file://得到引用记数 void AddAutoPtr(void * autoPtr,int AutoMark);//加入一个拥有该指针的灵巧指针 BOOL DeleteAutoPtr(void * autoPtr); file://释放一个灵巧指针的拥有权 void SetPtr(void * thePtr,int Size, int mark,int count=0); file://设置一个新的指针 void operator delete(void * p) { free(p); } void * operator new(size_t size) { return malloc(size); } private: int m_mark; file://指针标志 int m_count; file://引用记数 void * m_ptr; file://分配的指针 int m_size; file://指针指向内存的大小 CPtrArray AutoPtrArray; file://存放拥有该指针的所有灵巧指针的指针数组 CUIntArray m_AutoMark; file://灵巧指针标志:0 in the stack; >0 =mark CMutex mutex; file://用于线程同步 }; class CPtrManager { public: int GetAutoMark(void * ptr); file://通过灵巧指针的指针,得到灵巧指针标志 CPtrManager(); virtual ~CPtrManager(); int GetMarkFromPtr(void * Ptr); void *MallocPtr(size_t size); BOOL bCanWrite(); void DeletePtr(int mark,void * Ptr); void AddPtr(void *Ptr,int PtrSize); static CPtrManager * GetPtrManager(); CPtr * GetCPtr(void * Ptr,int mark);//通过指针和指针标志得到存放该指针的 CPtr private: CPtrArray m_ptr; file://存放 CPtr 的指针数组 void* pCurrent; unsigned int m_mark; CUIntArray m_removed; BOOL bWrite; file://在解决互锁现象的过程中,谢绝其它线程的处理 static CPtrManager * p_this; CMutex mutex;//用于线程同步 CMarkTable myMarkTable; void RemoveLockRes(); file://处理互锁内存 void CopyAllMark(); file://处理互锁现象前,先对所有的CPtr进行拷贝 static UINT myThreadProc(LPVOID lparm); file://处理互锁现象的线程函数 CWinThread* myThread; void BeginThread() { myThread=AfxBeginThread(myThreadProc,this,THREAD_PRIORITY_ABOVE_NORMAL);} }; 上面的应用中加入了灵巧指针的标志,其实,这个标志就等于该灵巧指针所存在的内存的指针的标志。例如:我们用 new 分配了一个 test 指针,假如这个指针的标志 mark=1,那么,这个 test 中的灵巧指针 auto_ptr p 的标志 automark=1。如果一个灵巧指针存在于栈中,那么它的 automark=0。反之亦然,如果一个灵巧指针的 automark 等于一个指针的 mark,那么,该灵巧指针必存在于这个指针所指的内存中。可是,如何得到这个标志呢,请看下面这个函数的实现: int CPtrManager::GetAutoMark(void *ptr) { CSingleLock singleLock(&mutex); singleLock.Lock(); file://线程同步 int size =m_ptr.GetSize(); for(int i=1;i { CPtr* theCPtr=(CPtr*)m_ptr[i]; if(theCPtr) { int ptrFirst=(int)theCPtr->GetPtr();//得到内存的首指针 int ptrEnd=ptrFirst+theCPtr->GetPtrSize();//得到内存的尾指针 int p=(int)ptr; file://灵巧指针的指针 if(p>=ptrFirst&&p<=ptrEnd)//比较灵巧指针的指针是否在首尾之间 return i; } } return 0; } 这个函数的原理就在于:如果一个灵巧指针存在于一块内存中,那么该灵巧指针的指针必在这块内存的首尾指针之间。 解决了灵巧指针的位置问题,下一步就是要找出所有被互锁的内存的指针。这个好实现,只要所有拥有这个指针的灵巧指针的 automark > 0 ,那么,这块内存就可能被互锁了(注意只是可能),接着看下面的实现: class CMark { friend class CMarkTable; public: CMark(){} virtual ~CMark(){} void operator delete(void * p) { free(p); } void * operator new(size_t size) { return malloc(size); } void CopyFromCPtr(CPtr* theCPtr); file://从 CPtr 中拷贝相关信息 BOOL bIsNoneInStack(); file://判断拥有该指针的所有灵巧指针是否都不在栈中 void Release(); file://解除该指针的互锁 private: int m_mark; file://指针的标志 CPtrArray autoptrArray; file://拥有该指针的所有灵巧指针的指针数组 CUIntArray automarkArray;//拥有该指针的所有灵巧指针的标志 }; class CMarkTable { public: CMarkTable(){Init();} virtual ~CMarkTable(){} void AddCMark(CMark * theCMark); BOOL FindMark(int mark); void Init(); void DoLockMark(); file://处理互锁问题 private: CPtrArray CMarkArray; file://暂存从CPtrManager 中拷贝过来的指针信息的 CMark 指针数组 CPtrArray CLockMarkArray; file://存放互锁的内存 void GetLockMark(); file://得到所有可能被互锁的内存的 CMark,结果存放于CLockMarkArray BOOL FindLockMark(int mark); file://判断一个灵巧指针是否存在于CLockMarkArray所包含的指针中 void RemoveUnlockMark();//去除假的互锁内存 void RemoveGroup(int automark);//对互相有联系的相互死锁的内存进行分组 }; 这里又引入了两个类:CMark 和 CMarkTable ,这是为了在处理互锁问题之前,对 CPtrManager 中的 CPtr 进行快速拷贝,以防止影响其它线程的正常运行。其实,这里的 CMark 与 CPtr 没有什么区别,它只是简单地从 CPtr 中拷贝信息,也就是说,它等同于 CPtr 。 为了处理互锁问题,先要把可能被互锁的内存指针找出来,看下面函数的实现: void CMarkTable::GetLockMark() { CLockMarkArray.SetSize(0); int size=CMarkArray.GetSize(); for(int i=0;i { CMark * theMark=(CMark*)CMarkArray[i]; if(theMark) { if(theMark->bIsNoneInStack()) CLockMarkArray.SetAtGrow(i,theMark); } } } 把这些内存找出来之后,就需要把那些假锁的内存找出来,什么是假锁呢?看下面的例子: 对于指针 ptrA ,如果它的灵巧指针 autoA 存在于指针 ptrB 中,而 ptrB 的灵巧指针 autoB 又存在于 ptrA 中,那么 ptrA 和 ptrB 是真锁,但是如果ptrB 的灵巧指针 autoB 存在于指针 ptrC 中,而 ptrC的灵巧指针 autoC 存在于栈中,那么, ptrA 和 ptrB 属于假锁。怎么找出假锁的内存呢?看下面函数的实现: void CMarkTable::RemoveUnlockMark() { CUIntArray UnlockMarkArray; BOOL bNoneRemoveed; do { bNoneRemoveed=TRUE; UnlockMarkArray.SetSize(0); int size=CLockMarkArray.GetSize(); for(int i=0;i { CMark * theMark=(CMark*)CLockMarkArray[i]; if(theMark) { int size1=(theMark->automarkArray).GetSize(); for(int j=0;j { int mark=(theMark->automarkArray)[j]; if(!FindLockMark(mark)) file://判断灵巧指针是否存在于CLockMarkArray所包含的指针中 { UnlockMarkArray.InsertAt(0,i); file://record to remove bNoneRemoveed=FALSE; break; } } } else { UnlockMarkArray.InsertAt(0,i); bNoneRemoveed=FALSE; } } int size2=UnlockMarkArray.GetSize(); for(int k=0;k { int m=UnlockMarkArray[k]; CLockMarkArray.RemoveAt(m); } }while(!bNoneRemoveed); } 上面函数的原理就是:不停地删除那些灵巧指针不在CLockMarkArray所包含的指针中的指针,直到所有的指针的灵巧指针都存在于CLockMarkArray所包含的指针中。 所有被互锁的内存被找出来了,那么,下一步就是如何解锁的问题了。由此,我对灵巧指针引入了一个父类parent_autoptr 如下: class parent_autoptr { public: parent_autoptr() {thisAutoMark=0;} virtual ~parent_autoptr(){} virtual void Release(){} file://释放指针的拥有权 protected: int thisAutoMark; file://存放灵巧指针标志 }; 在灵巧指针中,对函数 Release() 进行了重载。 template class auto_ptr :public parent_autoptr { public: virtual void Release(){Remove();} auto_ptr() {mark=0;pointee=0;thisAutoMark=GetAutoMark();} auto_ptr(auto_ptr&rhs); auto_ptr(T*ptr); ~auto_ptr(){Remove();} T*operator->() const; operator T*(); T&operator*()const; auto_ptr&operator=(auto_ptr&rhs); auto_ptr&operator=(T*ptr); private: void Remove(); int GetAutoMark(); CMutex *GetCMutex(); void ReadyWrite(); T*pointee; int mark; }; 在 CMarkTable 和 CMark 中对互锁内存进行了释放,如下: void CMarkTable::DoLockMark() { GetLockMark(); RemoveUnlockMark(); int size=CLockMarkArray.GetSize(); while(size) { CMark* theMark=(CMark*)CLockMarkArray[0]; CLockMarkArray.RemoveAt(0); if(theMark) { int size2=(theMark->automarkArray).GetSize(); for(int i=0;i { int automark=(theMark->automarkArray)[i]; RemoveGroup(automark); } theMark->Release(); } size=CLockMarkArray.GetSize(); } Init(); } void CMark::Release() { int size=autoptrArray.GetSize(); for(int i=0;i { parent_autoptr * thePtr=(parent_autoptr *)autoptrArray[i]; thePtr->Release(); } } 到了现在,终于算是大功告成了,我马上把它投入测试当中,发现工作得非常好,即使开辟20至30个线程,程序也工作得很好,并没有抛出异常,而且垃圾回收的功能也非常好。但是,如果线程太多,那么在 CPtrManager 中为了保证线程同步,将会造成瓶颈效应,严重者将会严重影响执行效率。同时,如果每个线程都不停地产生死锁内存,那么,垃圾回收将应接不暇,时间长了,也会造成系统的资源耗尽。 代码的使用很简单,你只需要将我所附的两个文件加入到工程中,然后,在你的 C*App 中加入如下一段代码就行了: CPtrManager thePtrManager; 这将保证 thePtrManager 在进程最后结束的时候才被析构。 如果你是在一个新的工程中使用,这就够了,但是,如果你还要使用原来的代码,特别是有指针参数的传递时,那么,你必须注意了。 如果需要从老代码中接收一个指针,而且这个指针需要你自己释放,那么可以使用灵巧指针,如果不需要释放,那么只能使用一般指针; 如果需要传递一个指针给老代码,而且这个指针需要你自己释放,那么可以使用灵巧指针,否则,只能使用一般指针。 <淘宝热门商品:
 

95.00 元 

宫廷古方秘制 丰胸食品18味 玉女补乳酥 粉粉

 

4.60 元  

旺智通讯手机配件商城-----诚邀各地商家加盟合作(可代发货)

皇冠推荐 特卖 诺基亚原装二手BL-5C电池 型号BL5C

来源:程序员网

小小豆叮

J2EE 组件开发:什么是消息驱动的EJB

消息服务是一种在分布式应用之间提供消息传递服务的软件,具有可靠、异步、宽松结 合、语言中立、平台中立的特点,而且通常是可配置的。它的实现原理是:对发送者和 接收者之间传递的消息进行封装,并在分布式消息客户程序结合的位置加上一个软件处 理层。消息服务为消息的客户程序提供了一个接口,这个接口隔离了底层的消息服务, 使得各种不同的客户程序能够通过一个友好的编程接口方便地通信。 Java消息服务(Java Message Service,JMS)是一个Java API,它定义了消息的客户程 序如何以一种标准化的形式与底层的消息服务提供者交互。JMS提供了一种接口,底层消 息服务提供者通过该接口向客户程序提供JMS消息服务。JMS提供了点对点消息模式(Po int-to-Point)和发布-订阅消息模式(Publish-Subscribe)。点对点消息模式通过一 个消息队列实现,消息的生产者向队列写入消息,消息的消费者从队列提取消息。发布 -订阅消息模式通过一个话题(Topic)节点构成的层次结构实现,消息的生产者向这个 层次结构发布消息,消息的消费者向这个结构订阅消息。 点对点消息模式具有如下特点: 每一个消息只有一个消费者。 消息的接收者和发送者之间不存在时间上的依赖关系。不论发送者发送消息时接收者是 否在运行,接收者都可以提取信息。 接收者对于成功处理的消息给出回执。 发布-订阅消息模式具有如下特点: 每一个消息可以有多个消费者。 向某个话题订阅的客户程序只能收到那些在它订阅之后发布的消息。为了接收到消息, 订阅者必须保持活动状态。因此,发布者和订阅者之间存在时间上的依赖关系。 JMS API在一定程度上放宽了对这种依赖关系的要求,允许创建持久性订阅(Durable S ubscription)。有了持久性订阅,当订阅者不活动时发送的消息也能接收到。 EJB 2.0规范定义了一种新的EJB类型,即消息驱动的EJB(Message-Driven EJB,简称M DB),它能够以EJB的形式实现JMS消息的接收者。消息驱动的EJB实现一组新的接口,这 组接口使得EJB能够异步地接收和处理JMS消息生产者发送到队列或话题的消息。EJB客户 程序的构造方式与普通JMS消息生产者的构造方式完全一样,也就是说,JMS消息生产者 不必知道消息的消费者是一个EJB。 相对于会话Bean和实体Bean而言,消息驱动的Bean最大的特点是客户程序不通过接口访 问Bean。与会话Bean和实体Bean不同,消息驱动的Bean只有一个Bean类。从某些方面看 ,消息驱动的Bean类似于无状态会话Bean: 消息驱动的Bean不为特定的客户保留数据或对话状态。 一个消息驱动Bean的所有的实例都是等价的,这使得容器能够把消息指派给任意一个消 息驱动Bean的实例。容器能够建立消息驱动Bean的缓冲池,实现消息的并发处理。 一个消息驱动的Bean能够处理来自多个客户程序的消息。 消息驱动Bean的实例变量可以在处理客户消息期间包含一些状态信息,例如JMS连接、打 开的数据库连接,或者是对EJB对象的引用。当一个消息到达,容器调用消息驱动Bean的 onMessage()方法处理消息。onMessage()方法通常把消息定型(cast)成为五种JMS消息 类型之一,然后按照应用的业务逻辑的要求处理消息。 传递给消息驱动Bean的消息可能处于一个事务之内,这时,onMessage()方法内的所有操 作都属于该事务的一部分。如果消息处理结果被回退,则系统将再次投递该消息。 哪些时候应该使用消息驱动的Bean呢?会话Bean和实体Bean能够发送JMS消息,能够同步 接收消息,但不能异步接收。一些时候,为防止过多地占用服务器资源,在服务器端的 组件中,我们想要避免阻塞,这时,我们可以用消息驱动的Bean异步接收消息。 二、MDB体系结构 图一描述了消息驱动的Bean组件的基本体系结构。 在图一中,位于顶端的是javax.ejb.EnterpriseBean接口,它是所有EJB的基础接口。E nterpriseBean接口派生出了javax.ejb.MessageDrivenBean接口,所有消息驱动的EJB类 必须实现javax.ejb.MessageDrivenBean接口。此外,消息驱动的Bean必须实现javax.j ms.MessageListener接口。公用的、非最终的、非抽象的消息驱动的EJB,比如图一显示 的MyMessageDrivenEJBean,必须同时实现MessageListener接口和MessageDrivenBean接 口。消息驱动的EJB与其他类型的EJB不同,它们不把业务方法导出给客户程序,它们关 心的只是遵从EJB容器的接口要求。由于这个原因,消息驱动的Bean必须有一个不需要参 数的公用构造方法(ejbCreate()方法),而且不应该实现finalize()方法。 2.1 MDB接口 在消息驱动的Bean中,setMessageDrivenContext()方法用来把一个MessageDrivenCont ext的对象实例传递给EJB,它是MessageDrivenBean接口定义中容器调用的第一个方法。 MessageDrivenContext对象封装了一个EJB消息驱动容器上下文的接口,支持消息驱动的 EJB实例访问容器提供的运行时消息驱动上下文 对于消息驱动的EJB来说,关键之一是要实现一个没有参数的ejbCreate()方法。当EJB容 器准备创建消息驱动EJB的实例时,它将调用这个方法。容器之所以决定创建某个EJB的 实例,可能是因为它要构造一个Bean实例的缓冲池,也可能是因为它接收到了客户的请 求。这个ejbCreate()方法和其他Bean上的EJB构造方法类似,属于EJB实现的一种特殊的 构造函数或初始化方法。 当EJB容器准备不让Bean实例继续处理客户程序的请求时,它就会调用消息驱动Bean的e jbRemove()方法。何时在消息驱动的Bean上调用ejbRemove()方法由EJB容器单独决定, 不受EJB客户程序的任何约束。应当注意的是,容器并不保证一定调用ejbRemove()方法 。在正常操作时,容器会调用ejbRemove()方法;但是,当消息驱动的Bean向容器抛出了 系统异常时,不能保证ejbRemove()方法一定会被调用。由于这个原因,Bean开发者必须 按时检查和清除Bean分配的所有资源。 对于Bean开发者来说,最重要的任务也许是实现onMessage()方法。当一个异步消息必须 由Bean实例处理时,容器将调用onMessage()方法。onMessage()方法的参数是一个普通 的JMS javax.jms.Message的实例,消息驱动的EJB实例从这个Message的实例提取待处理 的数据完成消息处理。 2.2 JMS消息接口 那么,在onMessage()方法调用传入的 JMS消息中,消息驱动的Bean如何提取信息,可以 提取哪些信息呢?图二描述了基本JMS消息类型的核心接口和概念。在一个以JMS为基础 的消息系统中,Message接口是在系统中传递的所有消息的最基本的接口(或称之为根接 口,Root Interface)。Destination接口描述了消息传递的一个终端;类似地,由于消 息有一个传递模式,所以图二还显示了Message接口与DeliveryMode接口的概念上的关系 。 JMS消息的头信息可以通过一组标准的方法设置或提取,这组标准方法的名字为getJMSX XX()或setJMSXXX()形式(下面我们分别称之为get方法和set方法),其中XXX是消息头 信息中的属性名字,例如getJMSDeliveryMode()方法。在Message接口中,通过get方法 和set方法操作的标准头信息属性包括:唯一的消息ID,时标(Timestamp),答复和目 标地址,消息传递模式,消息类型,以及消息的优先级。 在JMS消息中,JMS容器提供者特有的属性可以通过getXXXProperty()方法提取,或通过 setXXXProperty()方法设置,其中XXX表示属性的类型,例如byte getByteProperty(ja va.lang.String name)。每一个属性有一个通过String对象指定的名字和相应的值。名 字以JMSX前缀开头的属性作为标准JMS属性保留。 与消息正文数据(或称之为消息体,与消息头相对而言)的五种类型对应,五种消息类 型扩展了Message接口,如图三所示。Byte数据由BytesMessage封装,Serializable对象 由ObjectMessage封装,String消息由TextMessage封装,键-值对由MapMessage封装,I /O流由StreamMessage封装。 这些派生消息类型上的方法为特定类型的消息正文定义了get和set操作,而在Message基 础接口内,有一个通用的clearBody()方法,这个方法清除消息的正文,并把它置入只写 模式。clearBody()方法只清除消息正文,不清除消息头或属性。如果消息正文是只读的 ,调用该消息后,消息正文的状态将和新消息的空白正文状态一样。 2.3 MDB客户程序接口 消息驱动Bean的客户程序并不知道接收端实际处理消息的将是一个EJB。事实上,消息驱 动Bean的客户程序的构造方法与普通JMS客户程序的构造方法完全一样。 JMS的核心体系如图四所示。从图中我们可以看出,JMS ConnectionFactory(连接工厂 )初始上下文通过Java名称和目录接口(Java Naming and Directory Interface,JND I)创建。随后,连接工厂将用来创建与JMS服务提供者的连接。有了JMS连接,我们就可 以获得创建消息生产者和消息消费者的会话(Session)。实际上,消息驱动Bean的客户 程序就是消息的生产者,它发送的消息将由消息驱动的Bean(即消息消费者)接收。 三、点对点消息队列模式 图五显示了在一个支持点对点消息队列的系统中JMS的基本体系结构。消息队列体系实际 上是核心JMS体系的一个扩展,特别地,它加入了对消息队列功能的支持。连接工厂、连 接、会话、消息生产者、消息消费者等都用点对点消息队列形式的接口进行了扩展。 JMS客户程序利用JNDI获得一个QueueConnectionFactory对象的引用。随后,我们用Que ueConnectionFactory.createQueueConnection()方法之一创建一个QueueConnection对 象的实例。调用createQueueConnection()方法时可以指定一个用户名字和密码,或者, 我们也可以使用该方法不带参数的版本,此时假定使用默认用户身份。 QueueConnection接口是Connection接口的一种子类型,它代表着一个与JMS点对点消息 队列服务的连接。JMS客户程序调用createQueueSession()方法创建QueueSession的实例 ,createQueueSession()方法调用中一个boolean类型的参数指定了QueueSession对象是 否要提供事务支持。另外,回执的模式也在createQueueSession()调用中通过参数指定 ,这个参数的值可以是三个静态的标识符之一:AUTO_ACKNOWLEDGE,CLIENT_ACKNOWLED GE,DUPS_OK_ACKNOWLEDGE。 QueueSession.createQueue()方法返回一个Queue对象的实例,调用Queue.getQueueNam e()方法可以返回队列的名字。 QueueSession.createSender()方法创建一个QueueSender消息生产者,利用QueueSende r可以把消息发送到Queue。消息可以通过各种不同的QueueSender.send()方法发送到Qu eue,这些不同的send()方法能够把消息发送给QueueSender对象关联的Queue对象,或者 发送给send()方法调用中指定的Queue对象。消息递送模式、优先级、消息的有效时间都 可以在调用QueueSender.send()方法时指定。 发送给Queue的消息可以用Session接口中定义的各种消息构造方法创建。 四、发布-订阅消息模式 图六显示了在一个支持发布-订阅消息模式的系统中JMS的基本体系结构。发布-订阅消息 机制也是核心JMS机制的一种扩展,增加了一些适合发布-订阅消息模式的功能。连接工 厂、连接、会话、消息生产者、消息消费者等都用发布-订阅形式的接口进行了扩展。 JMS客户程序通过JNDI获得一个TopicConnectionFactory对象的引用。TopicConnection Factory.createTopicConnection()方法用来创建TopicConnection对象的实例。调用cr eateTopicConnection()方法时可以指定一个用户名字和密码,或者,我们也可以使用该 方法不带参数的版本,此时假定使用默认用户身份。 TopicConnection接口是Connection接口的一种子类型,它代表着一个与JMS发布-订阅消 息服务的连接。JMS客户程序调用TopicConnection.createTopicSession()方法创建Top icSession的实例。会话的事务支持和回执模式也在创建TopicSession时指定。 TopicSession.createTopic()方法返回一个Topic对象的实例。Topic接口封装了一个话 题目的地,发布者向该目的地发送消息,订阅者从该目的地接收消息。不同的服务提供 者按照不同的方式实现话题名称的层次结构,调用Topic.getTopicName()方法可以获得 话题的String形式的描述。 TopicSession.createPublisher()方法创建一个TopicPublisher消息生产者,它用来把 消息发布到Topic。消息可以通过各种不同的TopicPublisher.publish()方法发布到Top ic,这些不同的publish()方法能够把消息发送给TopicPublisher对象关联的Topic对象 ,或者发送给publish()方法调用中指定的Topic对象。消息递送模式、优先级、消息的 有效时间都可以在调用TopicPublisher.publish()方法时指定。 发送给Topic的消息可以用Session接口中定义的各种消息构造方法创建。 五、实例 本示例应用是一个消息驱动Bean应用的简单例子,由以下两部分构成: SimpleMessageClient:J2EE应用客户程序,向队列发送消息。 SimpleMessageEJB:一个消息驱动的Bean,异步地接收和处理由客户程序发送到队列的 消息。 图七描述了这个应用的结构。客户端应用把消息发送到队列,队列由管理员通过j2eead min命令创建。JMS提供者(这里是J2EE服务器)把消息传递给消息驱动Bean的实例,由 Bean的实例处理消息。 该示例应用的完整代码可以从本文最后下载。 5.1 客户端 SimpleMessageClient把消息发送到SimpleMessageBean监听的队列。客户程序首先确定 连接工厂和队列: queueConnectionFactory = (QueueConnectionFactory) jndiContext.lookup ("java:comp/env/jms/MyQueueConnectionFactory"); queue = (Queue) jndiContext.lookup("java:comp/env/jms/QueueName"); 接下来,客户程序创建队列连接、会话和一个消息发送器: queueConnection = queueConnectionFactory.createQueueConnection(); queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); queueSender = queueSession.createSender(queue); 最后,客户程序把几个消息发送到队列: message = queueSession.createTextMessage(); for (int i = 0; i < NUM_MSGS; i++) { message.setText("我是" + msgArray[i] ); System.out.println("Sending message: " + message.getText()); queueSender.send(message); } 5.2 MDB组件 SimpleMessageEJB类阐明了编写消息驱动Bean类的要求: 实现MessageDrivenBean接口和MessageListener接口。 类定义为public类型。 类不能定义成abstract或final。 实现一个onMessage()方法。 实现一个ejbCreate()方法和一个ejbRemove()方法。 包含一个public类型的不需要参数的构造方法。 不能定义finalize()方法。 与会话Bean和实体Bean不同,消息驱动的Bean不定义客户程序访问的接口。客户程序不 是先定位消息驱动的Bean,再调用这些Bean上的方法。虽然消息驱动的Bean没有业务方 法,但它们可以包含由onMessasge()方法内部调用的辅助方法。 当队列接收到一个消息,EJB容器将调用消息驱动Bean的onMessage()方法。在SimpleMe ssageBean类中,onMessage()方法把接收到的消息定型(cast)成为TextMessage类型, 然后显示出文本信息: public void onMessage(Message inMessage) { TextMessage msg = null; try { if (inMessage instanceof TextMessage) { msg = (TextMessage) inMessage; System.out.println("MESSAGE BEAN:收到消息: " + msg.getText()); } else { System.out.println("消息类型错误: " + inMessage.getClass().getName()); } } catch (JMSException e) { e.printStackTrace(); mdc.setRollbackOnly(); } catch (Throwable te) { te.printStackTrace(); } } 消息驱动Bean的ejbCreate()方法和ejbRemove()方法必须符合以下要求: 访问控制修饰符必须是public。 返回值类型必须是void。 不能有static和final修饰符。 throws子句不能定义任何应用自定义的异常。 不能带有参数。 在SimpleMessageBean类中,ejbCreate()方法和ejbRemove()方法都是空的,不执行任何 有实际意义的操作。 5.3 打包 接下来我们要把上面的应用打包成一个J2EE EAR文件。首先要把SimpleMessageEJB打包 成Jar文件。通常,打包过程可以通过工具完成,但理解模块部署描述器仍是必要的。在 EJB应用模块部署描述器中,顶级元素下面包含元素。下面可以包含一组元素(按照EJB 2.0新规范),每一个元素描述一个消息驱动Bean的配置和部署。 SimpleMessageEJB的ejb-jar.xml文件如下所示。元素内定义了消息驱动Bean的配置和部 署信息,例如唯一的Bean名字、Bean类的名字、配置参数、安全信息、事务信息、消息 目的地类型等。 ...... SimpleMessageJAR SimpleMessageEJB SimpleMessageEJB SimpleMessageBean Container javax.jms.Queue SimpleMessageEJB Bean onMessage javax.jms.Message Required 除了ejb-jar.xml部署描述器之外,通常还要有面向特定平台和环境的部署描述器。大多 数时候,这种描述器可以用GUI工具编写。请参见下载代码中提供的例子。 打包好各个模块之后,接着还要把J2EE应用打包成EAR文件。有关这一步骤的详细说明, 请参见开发平台的相关文档。本文以后有关部署和运行的说明,就以打包后的EAR文件为 基础。 5.4 部署和运行 假设我们在Sun的J2EE参考实现上部署和测试这个示例应用。为便于查看消息驱动Bean的 输出,我们必须以-verbose模式启动服务器: j2ee -verbose 用下面的j2eeadmin命令创建队列: j2eeadmin -addJmsDestination jms/MyQueue queue 验证队列已经创建成功: j2eeadmin -listJmsDestination 启动deploytool,选择菜单“File-->Open”,打开SimpleMessageApp.ear文件。接着, 选择菜单“Tools --> Deploy”,部署应用。出现部署提示时,选中“Return Client JAR”检查框。 在一个命令窗口中,进入EAR文件(SimpleMessageAppClient.jar文件)所在目录,把环 境变量APPCPATH设置为SimpleMessageAppClient.jar。然后,执行下面的命令: runclient -client SimpleMessageApp.ear -name SimpleMessageClient -textauth 在登录提示中,输入用户名字j2ee,输入密码j2ee。此时,客户程序将输出以下内容: Sending message: 我是老大孙悟空 Sending message: 我是老二猪八戒 Sending message: 我是老三沙和尚 在启动j2ee服务器的命令窗口,我们可以看到如下输出 <淘宝热门商品:
 

198元 

深深魅惑-*减肥*美容*收藏有惊喜:-)购物惊喜不断……

 

225.00 元  

上海商盟】易淘视听商城

五钻100%原装松下HTX7耳机经典白色 松下头戴式耳机 东方神起代言

来源:程序员网

小小豆叮

讲述java语言中内部类的研究

JAVA从JDK1.1开始引入了内部类,可以参见代码,感觉好处就是设计类的时候可以偷懒,呵呵。主要是可以引用类的内部其他元素,差不多是把这个内部类当成原类的元素。还有可以隐藏类的一些设计细节,好处还是很多的。 定义两个接口 package interfacepackage; public interface Destination { String readLabel(); } package interfacepackage; public interface Contents { int value(); } 一个类,并且加有测试代码 package debug; import interfacepackage.Contents; import interfacepackage.Destination; public class Tester { private int valueRate = 2; private class PContent implements Contents { private int i = 11 * valueRate; public int value() { return i; } } protected class PDestination implements Destination { private String label; private PDestination(String whereTo) { label = whereTo; } public String readLabel() { return label; } } public Destination dest(String s) { return new PDestination(s); } public Contents cont() { return new PContent(); } public static void main(String args[]) { Tester p = new Tester(); Contents c = p.cont(); System.out.println(c.value()); Destination d = p.dest("天外水火"); System.out.println(d.readLabel()); System.out.println("done"); } } 上面的代码是内部动态类,那么内部静态类是否也可以呢?答案是可以的,但是静态内部类是无法引用类的其他非静态元素的,例如上例中的PContent 内部类如果改为static类,是无法引用valueRate 属性的,这样是会报编译错误的,但是如果valueRate 如果也改为static是可以运行的。 <淘宝热门商品:
 

138.00 元 

专业定做925纯银 字母项链 刻字项链 名字项链

 

 

义乌三冠店→大量贩の热销女性用品(零售+批发)

来源:程序员网

小小豆叮

SSH的交互式Java应用开发和管理

启动演示 SSH Shell Server 引用 D:workspaceSecureJSH>ant demo Buildfile: build.xml build: compile-demo: run-java-demo: [java] SSH-2.0-SJSHD-1.0: Generating an authorized key for user sjsh... [java] SSH-2.0-SJSHD-1.0: New authorized private key for user sjsh stored to D:workspaceSecureJSHSJSH-Demo-Roothomesjsh.sshid_rsa [java] SSH-2.0-SJSHD-1.0: Updated authorized public keys for user sjsh stored to D:workspaceSecureJSHSJSH-Demo-Roothomesjsh.sshauthorized_keys [java] SSH-2.0-SJSHD-1.0(@localhost/127.0.0.1:22022): Starting... [java] SSH-2.0-SJSHD-1.0: Generating Host DSA Key... [java] SSH-2.0-SJSHD-1.0: Host DSA Key Stored to: D:workspaceSecureJSHSJSH-Demo-Rootetcsshssh_host_dsa_key [java] SSH-2.0-SJSHD-1.0: Host DSA Public Key Stored to: D:workspaceSecureJSHSJSH-Demo-Rootetcsshssh_host_dsa_key.pub [java] SSH-2.0-SJSHD-1.0: Generating Host RSA Key... [java] SSH-2.0-SJSHD-1.0: Host RSA Key Stored to: D:workspaceSecureJSHSJSH-Demo-Rootetcsshssh_host_rsa_key [java] SSH-2.0-SJSHD-1.0: Host RSA Public Key Stored to: D:workspaceSecureJSHSJSH-Demo-Rootetcsshssh_host_rsa_key.pub [java] SSH-2.0-SJSHD-1.0(@localhost/127.0.0.1:22022): Started. [java] Now you can login using an SSH client, with: [java] User Name: sjsh [java] Private Key: D:workspaceSecureJSHSJSH-Demo-Roothomesjsh.sshid_rsa [java] [java] Type in anything to stop: 然后通过任意SSH客户端连接上去: (注意OpenSSH客户端需要更改 SJSH-Roothomesjsh.sshid_rsa 的权限属性为 600, 其他客户端不支持PEM格式私钥的需要转换其格式, PuTTY 带的 PUTTYGEN 工具转换比较好用) 引用 Using username "sjsh". Authenticating with public key "imported-openssh-key" This is an interactive Java(TM) shell, type in Java(TM) statements to get them executed. Type in Ctrl^D to logout. Type in ? or help for a list of available commands. Type in to complete commands. Use UP/DOWN arrow keys for command history. Here you are in the demo shell. There are two demo built-in commands: msg and msgs, and one built-in field: msgs, those are added by this demo. Try them out and write your own shell similarly. SecueJSH Java(TM) Compiler Ready. [jsh ]$ ? Built-in commands: class + Start defining a new class in current package def [ [ <淘宝热门商品:
 

268.00 元 

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

 

12.00 元  

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

来源:程序员网

小小豆叮

讨论Ajax之所以优于JSF的原因

Sun为什么会搞出一个JSF,JSF为什么会是现在这个样子,我想原因是这样的: 首先,基于组件的Web开发将来会是一个趋势。自包含的组件便于IDE的处理,可以提高开发效率。 就是说JSF优于Struts/WebWork这类MVC框架的优势,在于它可以与IDE结合来自动生成代码。 而传统的纯手工编写的MVC框架,影响了开发效率。 因为Java技术在客户端并没有明显的优势。Applet已经被抛弃掉,Java的强项在服务器端。Sun不可能跑去使用JavaScript,因为在传统开发者眼里,JS只配做一点很琐碎的任务。 于是在他们设计的这个架构中,所有的用户事件都放在了服务器端来处理, 这个决策造成了JSF致命的缺点。它把事件处理模型绑死在服务器上,限制了响应性更加灵敏的交互设计。随之而来的网络延迟会毁掉软件的可用性。 这也是Ajax在JSF的架构中无法充分发挥作用的原因。 JSF的设计思路有点模仿VB,组件化的开发这个方向是没错的,Ajax开发将来也会走这条路。但是JSF与VB最大的差别是VB的事件模型都是位于本地来处理的。这是一种本质上的差别,所以如果JSF确实想模仿VB,那也是东施效颦。 而且在JSF的设计阶段,同步的请求/响应是主流,他们的思路仍然牢牢束缚在基于页面的开发方式上。根本就没有思考过其他的可能。 异步请求/响应是Ajax与传统开发方式最大的差别,异步带来了更好的交互设计。 在Ajax in Action第1章中作者举了一个令人信服的例子。Google Maps中当用户滚动地图时,获取新的地图图片,由于是异步请求的,因此不会打断用户的操作流程。 而在传统的地图服务,每次滚动可能都需要刷新页面。 用一下微软的那个地图服务就可以感觉到明显的差距,它甚至根本就不允许用户滚动地图。 http://terraserver.microsoft.com/ 以前我说Google Maps不是Ajax,因为没有使用XMLHttpRequest,这样说看来理解有些狭隘。 Google Maps请求地图的图片,采用的是修改动态创建的img元素的src属性的方式,这样的请求不会打断用户的操作,因此就是异步的。 我们在Ajax in Action中看到作者将Google Maps当作Ajax应用,而在Pragmatic Ajax中作者说Google Maps不是严格意义上的Ajax,两种说法都有道理。 JSF其实如果和Applet结合,可能更好些。Applet是多线程的,可以捕获用户的操作事件,采用异步方式发送到服务器。这样就不会打断用户的操作了。 但是这样一来设计的这个架构就复杂了。而且Applet是已经决定抛弃的东西。 JSF和Java Web Start结合也可以,不过JWS设计用来建造一类完全不同的Web应用,即Rich Client,而不是设计用来建造运行于浏览器之内的RIA应用。 所以JSF最多只是一种过渡方案,在Ajax/Flash的竞争下早已风光不在。 未来基于浏览器的RIA开发,Ajax、Flash是两种最有前途的技术。 按照泽欣的判断可能是三分天下,Ajax、Flash/Flex/Laszlo、还有M$的Atlas。 Atlas是M$开发的类似于Flash的一种技术,目前还只是一个vaporware,没有看到其庐山真面目。 Java Web Start相比之下只能局限于一些内部应用。 将来位于客户端的表现层开发可能会完全没有Java的位置,这是Sun不愿意看到的,但是Sun在这场角逐中只不过是一个小角色。 <淘宝热门商品:
 

19.00 元  

【广州商盟】靓一族专营匡威运动鞋/秋冬针织帽子

特价19元 09年新款出口韩国时尚个性净版球球针织帽爆款卷边

 

58.00 元  

淘宝生活 运动鞋专卖/正品ZIPPO热卖//淘宝职业信誉卖家

冲双钻 ADIDAS三叶草08夏季新款特价 漫画小子个性 休闲板鞋

来源:程序员网

小小豆叮

在Java程序中实现回调例程

熟悉 MS-Windows 和 X Window System 事件驱动编程模型的开发人员,习惯于传递在某种事件发生时调用(即“回调”)的函数指针。Java 的面向对象模型目前并不支持方法指针,这样似乎就不可能使用这种很好的机制。但我们并不是一点办法都没有! Java 的接口支持提供了一种获得回调的等价功能的机制。其技巧就是:定义一个简单接口,并在该接口中声明我们要调用的方法。 例如,假定我们希望在某个事件发生时得到通知。我们可以定义一个接口: public interface InterestingEvent { // 这仅是一个常规方法。因此如果需要, // 它可有返回值,也可接收参数。 public void interestingEvent (); } 这使得我们可以控制实现该接口的类的任何对象。因此,我们不必关心任何外部类型信息。与在将 C++ 代码用于 Motif 时使用窗口小部件的数据域来容纳对象指针的难以控制的 C 函数相比,这种方法要好得多。 发出事件信号的类必须等待实现了 InterestingEvent 接口的对象,并在适当时候调用 interestingEvent() 方法。 public class EventNotifier { private InterestingEvent ie; private boolean somethingHappened; public EventNotifier (InterestingEvent event) { // 保存事件对象以备后用。 ie = event; // 还没有要报告的事件。 somethingHappened = false; } //... public void doWork () { // 检查在别处设置的谓词。 if (somethingHappened) { // 通过调用接口的这个方法发出事件信号。 ie.interestingEvent (); } //... } // ... } 在上例中,我使用 somethingHappened 谓词来跟踪是否应触发事件。在许多情况下,调用此方法足以保证向 interestingEvent() 发出信号。 希望接收事件通知的代码必须实现 InterestingEvent 接口,并将自身引用传递给事件通知程序。 public class CallMe implements InterestingEvent { private EventNotifier en; public CallMe () { // 创建事件通知程序,并将自身引用传递给它。 en = new EventNotifier (this); } // 为事件定义实际的处理程序。 public void interestingEvent () { // 噢!必定发生了感兴趣的事件! // 执行某些操作 ... } //... } <淘宝热门商品:
 

4.00 元  

阳光网游挂机程序专业店

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

 

¥:38.00 

[郭氏鞋坊旗下]四季兜外贸童鞋店

185黑黄 库存外贸 DISNEY/迪斯尼Tigger&pooh童休闲运动鞋 带闪灯

来源:程序员网

小小豆叮

Java Socket编程简捷学习过程

第一步 充分理解Socket   1.什么是socket   所谓socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过"套接字"向网络发出请求或者应答网络请求。   以J2SDK-1.3为例,Socket和ServerSocket类库位于java.net包中。ServerSocket用于服务器端,Socket是建立网络连接时使用的。在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话。对于一个网络连接来说,套接字是平等的,并没有差别,不因为在服务器端或在客户端而产生不同级别。不管是Socket还是ServerSocket它们的工作都是通过SocketImpl类及其子类完成的。   重要的Socket API:   java.net.Socket继承于java.lang.Object,有八个构造器,其方法并不多,下面介绍使用最频繁的三个方法,其它方法大家可以见JDK-1.3文档。   . Accept方法用于产生"阻塞",直到接受到一个连接,并且返回一个客户端的Socket对象实例。"阻塞"是一个术语,它使程序运行暂时"停留"在这个地方,直到一个会话产生,然后程序继续;通常"阻塞"是由循环产生的。   . getInputStream方法获得网络连接输入,同时返回一个IutputStream对象实例,。   . getOutputStream方法连接的另一端将得到输入,同时返回一个OutputStream对象实例。   注意:其中getInputStream和getOutputStream方法均会产生一个IOException,它必须被捕获,因为它们返回的流对象,通常都会被另一个流对象使用。   2.如何开发一个Server-Client模型的程序   开发原理:   服务器,使用ServerSocket监听指定的端口,端口可以随意指定(由于1024以下的端口通常属于保留端口,在一些操作系统中不可以随意使用,所以建议使用大于1024的端口),等待客户连接请求,客户连接后,会话产生;在完成会话后,关闭连接。   客户端,使用Socket对网络上某一个服务器的某一个端口发出连接请求,一旦连接成功,打开会话;会话完成后,关闭Socket。客户端不需要指定打开的端口,通常临时的、动态的分配一个1024以上的端口。   {建立服务器} import java.net.*; import java.io.*; public class Server { private ServerSocket ss; private Socket socket; private BufferedReader in; private PrintWriter out; public Server() { try { ss = new ServerSocket(10000); while (true) { socket = ss.accept(); in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out = new PrintWriter(socket.getOutputStream(),true); String line = in.readLine(); out.println("you input is :" + line); out.close(); in.close(); socket.close(); } ss.close(); } catch (IOException e) {} } public static void main(String[] args) { new Server(); } }   这个程序建立了一个服务器,它一直监听10000端口,等待用户连接。在建立连接后给客户端返回一段信息,然后结束会话。这个程序一次只能接受一个客户连接。   {建立客户端} import java.io.*; import java.net.*; public class Client { Socket socket; BufferedReader in; PrintWriter out; public Client() { try { socket = new Socket("xxx.xxx.xxx.xxx", 10000); in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out = new PrintWriter(socket.getOutputStream(),true); BufferedReader line = new BufferedReader(new InputStreamReader(System.in)); out.println(line.readLine()); line.close(); out.close(); in.close(); socket.close(); } catch (IOException e) {} } public static void main(String[] args) { new Client(); } }   这个客户端连接到地址为xxx.xxx.xxx.xxx的服务器,端口为10000,并从键盘输入一行信息,发送到服务器,然后接受服务器的返回信息,最后结束会话。    第二步 多个客户同时连接   在实际的网络环境里,同一时间只对一个用户服务是不可行的。一个优秀的网络服务程序除了能处理用户的输入信息,还必须能够同时响应多个客户端的连接请求。在java中,实现以上功能特点是非常容易的。   设计原理:   主程序监听一端口,等待客户接入;同时构造一个线程类,准备接管会话。当一个Socket会话产生后,将这个会话交给线程处理,然后主程序继续监听。运用Thread类或Runnable接口来实现是不错的办法。   {实现消息共享} import java.io.*; import java.net.*; public class Server extends ServerSocket { private static final int SERVER_PORT = 10000; public Server() throws IOException { super(SERVER_PORT); try { while (true) { Socket socket = accept(); new CreateServerThread(socket); } } catch (IOException e) {} finally { close(); } } //--- CreateServerThread class CreateServerThread extends Thread { private Socket client; private BufferedReader in; private PrintWriter out; public CreateServerThread(Socket s) throws IOException { client = s; in = new BufferedReader(new InputStreamReader(client.getInputStream(), "GB2312")); out = new PrintWriter(client.getOutputStream(), true); out.println("--- Welcome ---"); start(); } public void run() { try { String line = in.readLine(); while (!line.equals("bye")) { String msg = createMessage(line); out.println(msg); line = in.readLine(); } out.println("--- See you, bye! ---"); client.close(); } catch (IOException e) {} } private String createMessage(String line) { xxxxxxxxx; } } public static void main(String[] args) throws IOException { new Server(); } } <淘宝热门商品:
 

199.00 元  

JACK JONES专柜正品白色内绒毛设计羊毛毛

 

3.50 元  

联达电子音响材料网淘宝分铺

【联达电子】镀银优质九脚电子管管座

来源:程序员网

小小豆叮

怎样读取和处理XML的配置文件

Java和XML是黄金组合,网上已经有很多文章介绍,XML作为电子商务中数据交换,已经有其不可替代的作用,但是在平时系统开发中,我们不一定都用到数据交换,是不是无法使用XML了? 当然不是,现在已经有一个新趋势,java程序的配置文件都开始使用XML格式,以前是使用类似windows的INI格式.(Java中也有Propertiesy这样的类专门处理这样的属性配置文件).使用XML作为Java的配置文件有很多好处,从Tomcat的安装配置文件和J2ee的配置文件中,我们已经看到XML的普遍应用,让我们也跟随流行趋势用XML武装起来. 现在关键是如何读取XML配置文件?有好几种XML解析器:主要有DOM和SAX ,这些区别网上文章介绍很多. 在apache的XML项目组中,目前有Xerces Xalan Cocoon几个开发XML相关技术的project.Tomcat本身使用的是 Sun 的 JAXP,而其XSL Taglib project中使用Xerces解析器. 好了,上面都是比较烦人的理论问题,还是赶快切入XML的配置文件的读取吧. 在我们的程序中,通常要有一些根据主机环境确定的变量.比如数据库访问用户名和密码,不同的主机可能设置不一样.只要更改XML配置文件,就可以正常运行. localhost sqlname username password 上面这个myenv.xml配置文件一般是放在tomcat的WEB-INF/classes目录下. 我们编制一个Java程序直接读取,将dbhost dbuser dbpassword提取出来供其他程序访问数据库用. 目前使用SAX比较的多,与DOM主要区别是 SAX是一行一行读取XML文件进行分析,适合比较大文件,DOM是一次性读入内存,显然不能对付大文件.这里我们使用SAX解析,由于SAX解析器不断在发展,网上有不少文章是针对老版本的.如果你使用JDK1.4 ,可以参考 使用SAX处理XML文档 一文.这里的程序是根据其改进并且经过实践调试得来的. 对上面myenv.xml读取的Java程序: import org.xml.sax.Attributes; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.SAXException; import java.util.Properties; //使用DefaultHandler的好处 是 不必陈列出所有方法, public class ConfigParser extends DefaultHandler { ////定义一个Properties 用来存放 dbhost dbuser dbpassword的值 private Properties props; private String currentSet; private String currentName; private StringBuffer currentValue = new StringBuffer(); //构建器初始化props public ConfigParser() { this.props = new Properties(); } public Properties getProps() { return this.props; } //定义开始解析元素的方法. 这里是将中的名称xxx提取出来. public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { currentValue.delete(0, currentValue.length()); this.currentName =qName; } //这里是将之间的值加入到currentValue public void characters(char[] ch, int start, int length) throws SAXException { currentValue.append(ch, start, length); } //在遇到结束后,将之前的名称和值一一对应保存在props中 public void endElement(String uri, String localName, String qName) throws SAXException { props.put(qName.toLowerCase(), currentValue.toString().trim()); } } 上面的这个解析程序比较简单吧? 其实解析XML就是这么简单. 现在我们已经将dbhost dbuser dbpassword的值localhost sqlname username password提取了出来.但是这只是在在解析器内部,我们的程序还不能访问.需要再编制一个程序. import java.util.Properties; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import java.net.URL; public class ParseXML{ //定义一个Properties 用来存放 dbhost dbuser dbpassword的值 private Properties props; //这里的props public Properties getProps() { return this.props; } public void parse(String filename) throws Exception { //将我们的解析器对象化 ConfigParser handler = new ConfigParser(); //获取SAX工厂对象 SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(false); factory.setValidating(false); //获取SAX解析 SAXParser parser = factory.newSAXParser(); //得到配置文件myenv.xml所在目录. tomcat中是在WEB-INF/classes //下例中BeansConstants是用来存放xml文件中配置信息的类,可以自己代替或定义 URL confURL = BeansConstants.class.getClassLoader().getResource(filename); try { //将解析器和解析对象myenv.xml联系起来,开始解析 parser.parse(confURL.toString(), handler); //获取解析成功后的属性 以后 我们其他应用程序只要调用本程序的props就可以提取出属性名称和值了 props = handler.getProps(); }finally{ factory=null; parser=null; handler=null; } } } 由于我们的XML文件是使用最简单的形式 ,因此解析器相对简单,但是这已经足够对付我们的配置文件了. <淘宝热门商品:
 

96.00 元 

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

 

26.00 元  

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

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

来源:程序员网

小小豆叮

通过Java Swing看透MVC设计模式

一个好的用户界面(GUI)的设计通常可以在现实世界找到相应的表现。例如,如果在您的面前摆放着一个类似于电脑键盘按键的一个简单的按钮,然而就是这么简单的一个按钮,我们就可以看出一个GUI设计的规则,它由两个主要的部分构成,一部分使得它具有了按钮应该具有的动作特性,例如可以被按下。另外一部分则负责它的表现,例如这个按钮是代表了A还是B。   看清楚这两点你就发现了一个很强大的设计方法,这种方法鼓励重用reuse,而不是重新设计redesign。你发现按钮都有相同的机理,你只要在按钮的顶上喷上不同的字母便能制造出“不同”的按钮,而不用为了每个按钮而重新设计一份图纸。这大大减轻了设计工作的时间和难度。   如果您把上述设计思想应用到软件开发领域,那么取得相似的效果一点都不让人惊奇。一个在软件开发领域应用的非常广泛的技术Model/View/Controller(MVC)便是这种思想的一个实现。   这当然很不错,但是或许您又开始疑惑这和java基础类JFC(Java Foundation Class)中的用户界面设计部分(Swing)又有什么关系呢?好的,我来告诉你。   尽管MVC设计模式通常是用来设计整个用户界面(GUI)的,JFC的设计者们却独创性的把这种设计模式用来设计Swing中的单个的组件(Component),例如表格Jtable,树Jtree,组合下拉列表框JcomboBox等等等等。这些组件都有一个Model,一个View,一个Controller,而且,这些model,view,controller可以独立的改变,就是当组件正在被使用的时候也是如此。这种特性使得开发GUI界面的工具包显得非常的灵活。   MVC设计模式把一个软件组件区分为三个不同的部分,model,view,controller。   Model是代表组件状态和低级行为的部分,它管理着自己的状态并且处理所有对状态的操作,model自己本身并不知道使用自己的view和controller是谁,系统维护着它和view之间的关系,当model发生了改变系统还负责通知相应的view。   View代表了管理model所含有的数据的一个视觉上的呈现。一个Model可以有一个以上的View,但是Swing中却很少有这样的情况。   Controller管理着model和用户之间的交互的控制。它提供了一些方法去处理当model的状态发生了变化时的情况。   使用键盘上的按钮的例子来说明一下:Model就是按钮的整个机械装置,View/Controller就是按钮的表面部分。   下面的图解释了如何把一个JFC开发的用户界面分为model,view,controller,注意,view/Controller被合并到了一起,这是MVC设计模式通常的用法,它们提供了组件的用户界面(UI)。   用Button的例子详细说明   为了更好的理解MVC设计模式和Swing用户界面组件之间的关系,让我们更加深入的进行分析。我将采用最常见的组件button来说明。   我们从model来开始。   Model   一个按钮的model所应该具备的行为由一个接口ButtonModel来完成。一个按钮model实例封装了其内部的状态,并且定义了按钮的行为。它的所有方法可以分为四类:   1、查询内部状态   2、操作内部状态   3、添加和删除事件监听器   4、发生事件 法。   程序员通常并不会直接和model以及view/controller打交道,他们通常隐藏于那些继承自java.awt.Component的组件里面了,这些组件就像胶水一样把MVC三者合三为一。也正是由于这些继承的组件对象,一个程序员可以很方便的混合使用Swing组件和AWT组件,然后,我们知道,Swing组件有很多都是直接继承自相应的AWT组件,它能提供比AWT组件更加方便易用的功能,所以通常情况下,我们没有必要混合使用两者。 一个实例   现在我们已经明白了Java类与MVC各个部分的对应关系,我们可以更加深入一点去分析问题了。下面我们将要讲述一个小型的使用MVC模式开发的例子。因为JFC十分的复杂,我只能把我的例子局限于一个用户界面组件里面(如果你猜是一个按钮的例子,那么你对了!)   让我们来看看这个例子的所有部分吧。   Button类   最显而易见的开始的地方就是代表了按钮组件本省的代码,因为这个类是大部分程序员会接触的。   就像我前面提到的,按钮用户界面组件类实际上就是model和view/controller的之间的黏合剂。每个按钮组件都和一个model以及一个controller关联,model定义了按钮的行为,而view/controller定义了按钮的表现。而应用程序可以在任何事件改变这些关联。让我们看看得以实现此功能的代码。 public void setModel(ButtonModel buttonmodel) {  if (this.buttonmodel != null)  {   this.buttonmodel.removeChangeListener(buttonchangelistener);   this.buttonmodel.removeActionListener(buttonactionlistener);   buttonchangelistener = null;   buttonactionlistener = null;  }  this.buttonmodel = buttonmodel;  if (this.buttonmodel != null)  {   buttonchangelistener = new ButtonChangeListener();   buttonactionlistener = new ButtonActionListener();   this.buttonmodel.addChangeListener(buttonchangelistener);   this.buttonmodel.addActionListener(buttonactionlistener);  }  updateButton(); } public void setUI(ButtonUI buttonui) {  if (this.buttonui != null)  {   this.buttonui.uninstallUI(this);  }  this.buttonui = buttonui;  if (this.buttonui != null)  {   this.buttonui.installUI(this);  }  updateButton(); } public void updateButton() {  invalidate(); }   在进入下一节之前,你应该多花一些时间来仔细阅读一下Button类的源代码。   ButtonModel类   ButtonModel维护着三种类型的状态信息:是否被按下(pressed),是否“武装上了”(armed),是否被选择(selected)。它们都是boolean类型的值。   一个按钮被按下(pressed)是指当鼠标在按钮上面的时候,按下鼠标但是还没有松开鼠标按钮的状态,及时用户此时把鼠标拖拽到按钮的外面也没有改变这种状态。   一个按钮是否“武装了”(armed)是指按钮被按下,并且鼠标还在按钮的上面。   一些按钮还可能被选择(selected),这种状态通过重复的点击按钮取得true或者false的值。   下面的代码是状态pressed的一个缺省的实现。状态armed以及selected实现的代码与之类似。ButtonModel类应该被继承,这样可以覆盖缺省的状态定义,实现有个性的按钮。 private boolean boolPressed = false; public boolean isPressed() {  return boolPressed; } public void setPressed(boolean boolPressed) {  this.boolPressed = boolPressed;  fireChangeEvent(new ChangeEvent(button)); }   在进入下一节之前,你应该多花一些时间来仔细阅读一下ButtonModel类的源代码。 ButtonUI类   按钮的view/controller是负责构建表示层的。缺省情况下它仅仅是用背景色画一个矩形而已,他们的子类继承了他们并且覆盖了绘制的方法,使得按钮可以有许多不同的表现,例如MOTIF,Windows 95,Java样式等等。 public void update(Button button, Graphics graphics) { } public void paint(Button button, Graphics graphics) {  Dimension dimension = button.getSize();  Color color = button.getBackground();  graphics.setColor(color);  graphics.fillRect(0, 0, dimension.width, dimension.height); }   ButtonUI类并不自己处理AWT事件,他们会使用一个定制的事件监听器把低级的AWT事件翻译为高级的Button模型期望的语义事件。下面就是安装/卸载事件监听器的代码。 private static ButtonUIListener buttonuilistener = null; public void installUI(Button button) {  button.addMouseListener(buttonuilistener);  button.addMouseMotionListener(buttonuilistener);  button.addChangeListener(buttonuilistener); } public void uninstallUI(Button button) {  button.removeMouseListener(buttonuilistener);  button.removeMouseMotionListener(buttonuilistener);  button.removeChangeListener(buttonuilistener); }   View/Controller实际上就是一些方法。他们不维护任何自己的状态信息。因此,许多按钮的实例可以共享一个ButtonUI实例。ButtonUI是通过在方面的参数列表里面加上按钮的引用来区分各个不同的按钮。   同样,希望你能多花一些时间来看看ButtonUI类,然后咱们进入下一节。   ButtonUIListener类   ButtonUIListener类可以帮助Button类去转变鼠标或者键盘的输入为对按钮模型的操作。这个监听器类实现了:MouseListener,MouseMotionListener,ChangeListener接口,并且处理一下事件: public void mouseDragged(MouseEvent mouseevent) {  Button button = (Button)mouseevent.getSource();  ButtonModel buttonmodel = button.getModel();  if (buttonmodel.isPressed())  {   if (button.getUI().contains(button, mouseevent.getPoint()))   {    buttonmodel.setArmed(true);   }   else   {    buttonmodel.setArmed(false);   }  } } public void mousePressed(MouseEvent mouseevent) {  Button button = (Button)mouseevent.getSource();  ButtonModel buttonmodel = button.getModel();  buttonmodel.setPressed(true);  buttonmodel.setArmed(true); } public void mouseReleased(MouseEvent mouseevent) {  Button button = (Button)mouseevent.getSource();  ButtonModel buttonmodel = button.getModel();  buttonmodel.setPressed(false);  buttonmodel.setArmed(false); } public void stateChanged(ChangeEvent changeevent) {  Button button = (Button)changeevent.getSource();  button.repaint(); }   总结   我希望你能按照上面讲述的方法去做。如果不能,那么所有的努力都将白费。这个例子以及Swing用户界面组件的好处在于你不用去花时间去弄明白他们底层是如何设计实现的就可以很方便的使用他们了。他们都提供了缺省的model以及view/controller,然后,当你自己做组件的时候,你会发现上面的思想的强大之处。 <淘宝热门商品:
 

156.0元  

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

 

网络游戏点卡 

网游点卡武汉移动话费自动充专卖店

来源:程序员网

小小豆叮

如何动态调用之Java脚本API

我们不需要将动态语言编译为 Java字节码就可以在 Java 应用程序中使用它们。使用 Java Platform, Standard Edition 6 (Java SE)中添加的脚本包(并且向后兼容 Java SE 5),Java 代码可以在运行时以一种简单的、统一的方式调用多种动态语言。本系列文章共分两个部分,第 1 部分将介绍 Java 脚本 API 的各种特性。文章将使用一个简单的 Hello World 应用程序展示 Java 代码如何执行脚本代码以及脚本如何反过来执行 Java 代码。第 2 部分将深入研究 Java 脚本 API 的强大功能。   Java 开发人员清楚 Java 并不是在任何情况下都是最佳的语言。今年,1.0 版本的 JRuby 和 Groovy 的发行引领了一场热潮,促使人们纷纷在自己的 Java 应用程序中添加动态语言。Groovy、JRuby、Rhino、Jython 和一些其他的开源项目使在所谓的脚本语言中编写代码并在 JVM 中运行成为了可能(请参阅 参考资料)。通常,在 Java 代码中集成这些语言需要对各种解释器所特有的 API 和特性有所了解。   Java SE 6 中添加的 javax.script 包使集成动态语言更加容易。通过使用一小组接口和具体类,这个包使我们能够简单地调用多种脚本语言。但是,Java 脚本 API 的功能不只是在应用程序中编写脚本;这个脚本包使我们能够在运行时读取和调用外部脚本,这意味着我们可以动态地修改这些脚本从而更改运行应用程序的行为。   Java 脚本 API   脚本与动态的对比   术语脚本 通常表示在解释器 shell 中运行的语言,它们往往没有单独的编译步骤。术语动态 通常表示等到运行时判断变量类型或对象行为的语言,往往具有闭包和连续特性。一些通用的编程语言同时具有这两种特性。此处首选脚本语言 是因为本文的着重点是 Java 脚本 API,而不是因为提及的语言缺少动态特性。   2006 年 10 月,Java 语言添加了脚本包,从而提供了一种统一的方式将脚本语言集成到 Java 应用程序中去。对于语言开发人员,他们可以使用这个包编写粘连代码(glue code),从而使人们能够在 Java 应用程序中调用他们的语言。对于 Java 开发人员,脚本包提供了一组类和接口,允许使用一个公共 API 调用多种语言编写的脚本。因此,脚本包类似于不同语言(比如说不同的数据库)中的 Java Database Connectivity (JDBC) 包,可以使用一致的接口集成到 Java 平台中去。   以前,在 Java 代码中,动态调用脚本语言涉及到使用各种语言发行版所提供的独特类或使用 Apache 的 Jakarta Bean Scripting Framework (BSF)。BSF 在一个 API 内部统一了一组脚本语言(请参阅 参考资料)。使用 Java SE 6 脚本 API,二十余种脚本语言(AppleScript、Groovy、JavaScript、Jelly、PHP、Python、Ruby 和 Velocity)都可以集成到 Java 代码中,这在很大程序上依赖的是 BSF。   脚本 API 在 Java 应用程序和外部脚本之间提供了双向可见性。Java 代码不仅可以调用外部脚本,而且还允许那些脚本访问选定的 Java 对象。比如说,外部 Ruby 脚本可以对 Java 对象调用方法,并访问对象的属性,从而使脚本能够将行为添加到运行中的应用程序中(如果在开发时无法预计应用程序的行为)。   调用外部脚本可用于运行时应用程序增强、配置、监控或一些其他的运行时操作,比如说在不停止应用程序的情况下修改业务规则。脚本包可能的作用包括:   ·在比 Java 语言更简单的语言中编写业务规则,而不用借助成熟的规则引擎。   ·创建插件架构,使用户能够动态地定制应用程序。   ·将已有脚本集成到 Java 应用程序中,比如说处理或转换文件文章的脚本。   ·使用成熟的编程语言(而不是属性文件)从外部配置应用程序的运行时行为。   ·在 Java 应用程序中添加一门特定于域的语言(domain-specific language)。   ·在开发 Java 应用程序原型的过程中使用脚本语言。   ·在脚本语言中编写应用程序测试代码。   你好,脚本世界   HelloScriptingWorld 类(本文中的相关代码均可从 下载部分 获得)演示了 Java 脚本包的一些关键特性。它使用硬编码的 JavaScript 作为示例脚本语言。此类的 main() 方法(如清单 1 所示)将创建一个 JavaScript 脚本引擎,然后分别调用五个方法(在下文的清单中有显示)用于突出显示脚本包的特性。   清单 1. HelloScriptingWorld main 方法 public static void main(String[] args) throws ScriptException, NoSuchMethodException { ScriptEngineManager scriptEngineMgr = new ScriptEngineManager(); ScriptEngine jsEngine = scriptEngineMgr.getEngineByName("JavaScript"); if (jsEngine == null) { System.err.println("No script engine found for JavaScript"); System.exit(1); } System.out.println("Calling invokeHelloScript..."); invokeHelloScript(jsEngine); System.out.println(" Calling defineScriptFunction..."); defineScriptFunction(jsEngine); System.out.println(" Calling invokeScriptFunctionFromEngine..."); invokeScriptFunctionFromEngine(jsEngine); System.out.println(" Calling invokeScriptFunctionFromJava..."); invokeScriptFunctionFromJava(jsEngine); System.out.println(" Calling invokeJavaFromScriptFunction..."); invokeJavaFromScriptFunction(jsEngine); }   main() 方法的主要功能是获取一个 javax.script.ScriptEngine 实例(清单 1 中的前两行代码)。脚本引擎可以在特定的语言中加载并执行脚本。它是 Java 脚本包中使用最为频繁、作用最为重要的类。我们从 javax.script.ScriptEngineManager 获取一个脚本引擎(第一行代码)。通常,程序只需要获取一个脚本引擎实例,除非使用了很多种脚本语言。   ScriptEngineManager 类   ScriptEngineManager 可能是脚本包中惟一一个经常使用的具体类;其他大多数都是接口。它或许是脚本包中惟一的一个要直接或间接地(通过 Spring Framework 之类的依赖性注入机制)实例化的类。ScriptEngineManager 可以使用以下三种方式返回脚本引擎:   ·通过引擎或语言的名称,比如说 清单 1 请求 JavaScript 引擎。   ·通过该语言脚本共同使用的文件扩展名,比如说 Ruby 脚本的 .rb。   ·通过脚本引擎声明的、知道如何处理的 MIME 类型。      本文示例为什么要使用 JavaScript?   本文中的 Hello World 示例使用了部分 JavaScript 脚本,这是因为 JavaScript 代码易于理解,不过主要还是因为 Sun Microsystems 和 BEA Systems 所提供的 Java 6 运行时环境附带有基于 Mozilla Rhino 开源 JavaScript 实现的 JavaScript 解释器。使用 JavaScript,我们无需在类路径中添加脚本语言 JAR 文件。   ScriptEngineManager 间接查找和创建脚本引擎。也就是说,当实例化脚本引擎管理程序时,ScriptEngineManager 会使用 Java 6 中新增的服务发现机制在类路径中查找所有注册的 javax.script.ScriptEngineFactory 实现。这些工厂类封装在 Java 脚本 API 实现中;也许您永远都不需要直接处理这些工厂类。   ScriptEngineManager 找到所有的脚本引擎工厂类之后,它会查询各个类并判断是否能够创建所请求类型的脚本引擎 —— 清单 1 中为 JavaScript 引擎。如果工厂说可以创建所需语言的脚本引擎,那么管理程序将要求工厂创建一个引擎并将其返回给调用者。如果没有找到所请求语言的工厂,那么管理程序将返回 null,清单 1 中的代码将检查 null 返回值并做出预防。 <淘宝热门商品:
 

 

【杭州商盟】快美影像中心

 

288.00 元 

【19shop 超值正品】英国TOPMAN经典修

来源:程序员网

小小豆叮