将java更改为支持java 静态库 动态库和动态类型会有用吗

博客分类:
JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。 按照代理的创建时期,代理类可以分为两种。 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 动态代理:在程序运行时,运用反射机制动态创建而成。
首先看一下静态代理: 1、Count.java
package net.battier.
public interface Count {
public void queryCount();
public void updateCount();
2、CountImpl.java
package net.battier.dao.
import net.battier.dao.C
public class CountImpl implements Count {
public void queryCount() {
System.out.println("查看账户方法...");
public void updateCount() {
System.out.println("修改账户方法...");
、CountProxy.java
package net.battier.dao.
import net.battier.dao.C
public class CountProxy implements Count {
private CountImpl countI
public CountProxy(CountImpl countImpl) {
this.countImpl = countI
public void queryCount() {
System.out.println("事务处理之前");
countImpl.queryCount();
System.out.println("事务处理之后");
public void updateCount() {
System.out.println("事务处理之前");
countImpl.updateCount();
System.out.println("事务处理之后");
3、TestCount.java
package net.battier.
import net.battier.dao.impl.CountI
import net.battier.dao.impl.CountP
public class TestCount {
public static void main(String[] args) {
CountImpl countImpl = new CountImpl();
CountProxy countProxy = new CountProxy(countImpl);
countProxy.updateCount();
countProxy.queryCount();
观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。 再来看一下动态代理: JDK动态代理中包含一个类和一个接口: InvocationHandler接口: public interface InvocationHandler { public Object invoke(Object proxy,Method method,Object[] args) throws T } 参数说明: Object proxy:指被代理的对象。 Method method:要调用的方法 Object[] args:方法调用时所需要的参数
可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。
Proxy类: Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法: public static Object newProxyInstance(ClassLoader loader, Class&?&[] interfaces, InvocationHandler h)
throws IllegalArgumentException 参数说明: ClassLoader loader:类加载器 Class&?&[] interfaces:得到全部的接口 InvocationHandler h:得到InvocationHandler接口的子类实例
Ps:类加载器 在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器; Booststrap ClassLoader:此加载器采用C++编写,一般开发中是看不到的; Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类; AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。
动态代理 与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
动态代理示例: 1、BookFacade.java
package net.battier.
public interface BookFacade {
public void addBook();
2、BookFacadeImpl.java
package net.battier.dao.
import net.battier.dao.BookF
public class BookFacadeImpl implements BookFacade {
public void addBook() {
System.out.println("增加图书方法。。。");
、BookFacadeProxy.java
package net.battier.
import java.lang.reflect.InvocationH
import java.lang.reflect.M
import java.lang.reflect.P
public class BookFacadeProxy implements InvocationHandler {
public Object bind(Object target) {
this.target =
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result=null;
System.out.println("事物开始");
result=method.invoke(target, args);
System.out.println("事物结束");
3、TestProxy.java
package net.battier.
import net.battier.dao.BookF
import net.battier.dao.impl.BookFacadeI
import net.battier.proxy.BookFacadeP
public class TestProxy {
public static void main(String[] args) {
BookFacadeProxy proxy = new BookFacadeProxy();
BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());
bookProxy.addBook();
但是,JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。
Cglib动态代理 JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 示例 1、BookFacadeCglib.java
package net.battier.
public interface BookFacade {
public void addBook();
2、BookCadeImpl1.java
package net.battier.dao.
public class BookFacadeImpl1 {
public void addBook() {
System.out.println("增加图书的普通方法...");
3、BookFacadeProxy.java
package net.battier.
import java.lang.reflect.M
import net.sf.cglib.proxy.E
import net.sf.cglib.proxy.MethodI
import net.sf.cglib.proxy.MethodP
public class BookFacadeCglib implements MethodInterceptor {
public Object getInstance(Object target) {
this.target =
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this);
return enhancer.create();
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("事物开始");
proxy.invokeSuper(obj, args);
System.out.println("事物结束");
return null;
4、TestCglib.java
package net.battier.
import net.battier.dao.impl.BookFacadeImpl1;
import net.battier.proxy.BookFacadeC
public class TestCglib {
public static void main(String[] args) {
BookFacadeCglib cglib=new BookFacadeCglib();
BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());
bookCglib.addBook();
浏览: 41590 次
来自: 北京
总结的很好,谢谢分享
哇!总结的太好了。。凤哥哥,你好强大啊。。请问您跟凤姐什么关系 ...
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'java 反射 动态调用不同类的静态方法(推荐)_java
作者:用户
本文讲的是java 反射 动态调用不同类的静态方法(推荐)_java,
准备调用的类
public class Use {
public static Integer
demo( String s ){
System.err.println(s+&&&&
准备调用的类
public class Use {
public static Integer
demo( String s ){
System.err.println(s+"&&&&&&成功!");
Integer ss=1;
执行调用的类
public class Ceshi {
public static void main(String[] args) {
String className = "ss.Use";
Class&?& testClass = Class.forName(className);
Method saddMethod2 = testClass.getMethod("demo", new Class[]{String.class});
String result=saddMethod2.invoke(null,new Object[]{"测试反射"}).toString();
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
以上这篇JAVA 反射 动态调用不同类的静态方法(推荐)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持云栖社区。
以上是云栖社区小编为您精心准备的的内容,在云栖社区的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索java反射调用静态方法、java动态调用静态方法、反射调用静态方法、c 反射调用静态方法、ios 反射调用静态方法,以便于您获取更多的相关知识。
稳定可靠、可弹性伸缩的在线数据库服务,全球最受欢迎的开源数据库之一
6款热门基础云产品6个月免费体验;2款产品1年体验;1款产品2年体验
弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率
开发者常用软件,超百款实用软件一站式提供
云栖社区(yq.aliyun.com)为您免费提供相关信息,包括
java反射调用静态方法、java动态调用静态方法、反射调用静态方法、c 反射调用静态方法、ios 反射调用静态方法的信息
,所有相关内容均不代表云栖社区的意见!如何在Java平台上使用脚本语言做Java开发
最近开始流行区分Java平台和Java语言,但很多Java开发者还是不能确定如何在Java应用程序开发中结合脚本。本篇文章,Gregor Roth给出了在Java平台上使用脚本的方法。通过这篇文章,你可以了解怎样在你的Java应用程序中使用脚本,是否你要通过使用Groovy和Jython把不同的Java应用程序模块粘合在一起,或者写一个你自己的基于JRuby的应用程序,适用于Java平台。
作为一个Java开发者,你可能已经注意到了,Java语言已经不是Java平台的唯一所有者。Groovy也是一种适用于Java平台的编程语言,而且还有很多其他语言的解释器和编译器,都可以运行于Java虚拟机(JVM)之上,其中最流行的就是Jython和JRuby。另外,Java SE 6内置对于脚本引擎的支持,JSR 223定义了一个标准接口,与运行于Java平台的动态语言进行交互。
为了能在Java平台上做脚本开发,你需要清楚地理解所要面临的挑战和获得的好处。你需要理解从JRuby和 Jython写成的脚本中调用Java类时会发生什么事情,你同样需要知道要集成一个脚本语言到Java平台会遇到的困难,在你的开发过程中会产生什么样的影响。最后,你应该知道至少一些流行的脚本语言的不同特征,这样你才能知道他们适合放在你的程序的什么地方。
本篇文章概括了一些脚本语言(如Groovy,Jruby,Jython)和Java语言的区别,论述了一些在Java平台上使用脚本将会面临的挑战。同时,本文介绍了一些方法,使你可以集成一些最初由Ruby或Python写成的脚本到你的Java代码中。
静态类型VS动态类型
大部分脚本语言都是动态类型语言,而Java是一种静态类型语言。静态类型语言在声明变量的时候需要定义变量的类型,而且变量的值也只能设置成给定的类型的值。与之相反,动态类型语言不需要程序员给出清楚的类型定义,因为类型信息附属于变量值,而不是变量。通过下面的列表1可以看到,Groovy定义的变量V1可以被赋予任意不同类型的值。
列表1:Groovy动态类型
def v1 = '66'&&&&& // sets the variable with a value of type Stringprintln v1.dump()// prints out:// & value=[6, 6] offset=0 count=2 hash=1728&v1 = 9&&&&&&&&&&& // resets the variable with a value of type Integerprintln v1.dump()// prints out:// & value=9&
动态类型脚本语言的一种典型的实现方法,就是一直保持变量值和它的类型的可变性标签。当在操作中使用任何变量之前,才立即进行类型检查。这种做法的缺点就是在运行时需要额外的处理循环来确定变量值的类型和进行类型检查。但静态类型的提倡者指出,使用动态类型语言总是导致性能不足。
弱类型 VS 强类型
一些流行的脚本语言都是弱类型。弱类型语言允许在不同的类型上进行操作。弱类型语言支持隐式类型转换或多态。例如列表2所示,Groovy允许在一个整型和字符串型上进行加操作。
列表2:Groovy弱类型的例子
def v1 = '66'&&&&&&&& // set v1 with a String typed valuedef v2 = 5&&&&&&&&&&& // set v2 with a Integer typed valuedef v3 = v1 + v2println v3// prints out: // 665
与Groovy一样,Python也是一个动态类型语言。但与Groovy相比,Python却是一个强类型语言,所以它不支持上述操作。强类型没有弱类型那么宽松,不允许不同类型之间的混合操作,见列表3。
列表3:Python强类型的例子
v1 = '66'&&&&&&&&&&&&& # set v1 with a String typed valuev2 = 5&&&&&&&&&&&&&&&& # set v2 with a Integer typed valuev3 = v1 + v2# prints out:# TypeError: cannot concatenate 'str' and 'int' objects
静态,强类型的Java语言,在声明时,对于对象类型有最强可能性的约束。例如,如果想用Java实现一个回调模式,需要先写一个回调接口,定义回调函数,声明返回值类型,以及所有参数和定义异常类型。具体的回调实现将通过使用这个接口进行引用和调用,见列表4。
列表4:Java回调模式的实现
// the call back handler definition&&&&&&& interface IDataHandler {&&&&&&&&&&&&&&& public boolean onData(INonBlockingConnection nbc) throws IOE&&&&&&& }&&&&&&& // the server receives data and performs the handler's call back method&&&&&&& class MultithreadedServer {&&&&&&&&&&&&&&&& private volatile boolean isRunning =&&&&&&&&&&&&&&&& private IDataHandler dataHandler =&&&&&&&&&&&&&&& // accepts only an object which implements the IDataHandler interface&&&&&&&&&&&&&&& MultithreadedServer(IDataHandler dataHandler) {&&&&&&&&&&&&&&&&&&&&&&& this.dataHandler = dataH&&&&&&&&&&&&&&& }&&&&&&&&&&&&&&& public void run() {&&&&&&&&&&&&&&&&&&&&&& while (isRunning) {&&&&&&&&&&&&&&&&&&&&&&&&&& // waiting for data&&&&&&&&&&&&&&&&&&&&&&&&&& // ...&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&& // ... and dispatch it&&&&&&&&&&&&&&&&&&&&&&&&&& dataHandler.onData(nbc);&&&&&&&&&&&&&&&&&&&&&& }&&&&&&&&&&&&&&& }&&&&&&& }&&&&&&& // the call back implementation&&&&&&& class SmtpProtocolHandler implements IDataHandler {&&&&&&&&&&&&&&& public boolean onData(INonBlockingConnection nbc) throws IOException {&&&&&&&&&&&&&&&&&&&& SmtpSession session = (SmtpSession) nbc.getAttachment();&&&&&&&&&&&&&&&&&&&& //...&&&&&&&&&&&&&&& }&&&&&&& }&&&&&&& MultithreadedServer server = new MultithreadedServer(new SmtpProtocolHandler());&&&&&&& server.run();
它走起路来是否像一个鸭子?
当使用如Rython,Ruby或Groovy这样的脚本语言的时候,不需要定义像上面列表4定义的那样的接口。变量可以拥有任意对象类型的引用。当发送一个消息给目标对象的时候,语言的runtime检查是否存在一个匹配的方法,然后调用这个方法;否则,就抛出一个异常。目标对象不需要实现特殊的接口或是继承类。如果方法本身就存在,runtime就会自动调用它。这种行为被称作“duck typing”,(鸭子测试)意思就是“如果它看起来像一个鸭子,而且像鸭子一样呷呷地叫,那么它一定是一个鸭子。”
列表5:用Groovy写的回调处理
// the call back implementation (which doesn't implement any interface)&&&&&&& class SmtpProtocolHandler {&&&&&&&&&&&&&&& def onData(nbc) {&&&&&&&&&&&&&&&&&&&& def session = nbc.attachment&&&&&&&&&&&&&&&&&&&& //... &&&&&&&&&&&&&&& }&&&&&&& }&&&&&&& def server = new MultithreadedServer(new SmtpProtocolHandler())&&&&&&& server.run()
质量和性能
比较上面列表4和列表5的两段handler代码,很显然地发现,脚本语言代码比Java代码更紧凑,更易读。这主要是因为使用Groovy和JRuby,你就不需要像使用Java(静态,强类型语言)那样写出所有的类型声明。但在另一方面,缺失类型信息也存在一些缺点。静态类型的支持者称:静态,强类型语言可以通过在编译时检测类型错误来保证程序的健壮性;动态语言的支持者称:相反,像测试驱动开发这样的开发技术抵消了编译时检查的优点。
一般而言,脚本语言比系统程序语言运行的慢,但是运行时性能并不是要考虑的唯一问题。问题始终是,对于目标底层结构来说,是否执行起来足够快。除了速度需求,其它像可靠性和可变性之类的质量问题也需要考虑。例如,在整个软件生命周期中,维护费用占总体开销的比例最大。减少维护费用的关键就是提高可靠性和简易性。脚本语言比较简单,在这些方面通常就比像C++或Java这样的系统程序语言有更好的效果。
在Java平台上使用脚本的方法
现在,你不需要在使用Java和像Groovy,Ruby或Python这样的脚本语言之间做选择了。你的应用程序可以同时享用脚本语言的效率、简洁和Java平台的可靠性。在Java平台上使用脚本语言的关键是,要知道在哪儿用脚本语言最好,在哪儿用Java代码最好。
过去,脚本语言被看作是与Java组件连接在一起的一个细小的粘合代码层。现在,很多Java开发者在Java平台上使用脚本语言,完成很多工作,他们只是依靠Java类库来提供那些不被他们所使用的脚本支持的特征(例如,Java平台提供很多企业层的特征,这些特征大部分脚本语言环境都不支持,如事务管理,remoting通信,或是监测。)
不管你怎样使用它,脚本语言和Java平台的无缝粘合产生了一个更富足的开发环境,在这个环境下,你可以为恰当的任务选择恰当的语言。
有两种方法可以使你认识到什么是Java平台上的“polyglot”开发环境(完整开发环境):你可以或者在Java虚拟机上运行你自己的脚本,或者使用Java本身的接口/进程间通信,来在一个本身的脚本环境内执行脚本语言。
大多数流行的脚本语言的runtimes都是基于C/C++的。使用JNI,可以把你的Java环境连接到本身的脚本环境。对于Ruby,你可以使用一个基于JNI的解决方案(如RJB),或者一个基于进程间的解决方案(如YAJB)。遗憾的是,很多解决方案都会有一些不合需求的限制。例如,基于进程间的解决方案使用一个远程协议连接到当前环境,这可能会导致性能瓶颈。
基于Java的脚本runtime (动态语言支撑的结构)实现
开源工程,如Jython或JRuby被认为是纯粹的基于Java的脚本runtime实现,使你能够在Java虚拟机上执行Python或Ruby脚本。这意味着,使用Python或Ruby写成的脚本可以运行在拥有Java SE runtime的所有平台上。基于Java的脚本rutimes只是会首先把脚本语言结合到Java平台里,并不提供你所想象的那些功能。
因为最初的Ruby或Python脚本的runtimes比基于Java的快很多,使用本身的runtime会是处理这些脚本的首选。而JRuby和Jython这些语言的真正的价值是它们可以调用Java类和被Java类调用。这就把整个Java世界开放到了脚本语言。脚本语言可以访问任何由Java实现的事情。
从底层结构来看,JRuby或Jython可以被看作是基于Java的脚本runtimes,来在Java平台上执行正规的Ruby或Python脚本。从开发者角度看,JRuby或Jython可以被看作是丰富的脚本,它们使用Java类,需要格外的脚本runtime性能。因此,这些“J 脚本”不能执行在本身的脚本runtime上。
集成脚本到Java中
为了在Java虚拟机上运行Python,Ruby或Groovy,需要在Java classpath里添加基于Java的脚本runtimes的jars。设置完后,脚本引擎被实例化,就可以在Java环境里执行脚本了。大多数情况下,会为脚本执行提供简单的引擎类,如列表6所示:
列表6:为Ruby,Groovy,Python提供的Rutime引擎
// run a Ruby scripting& (JRuby V1.1b1)Ruby runtime = Ruby.getDefaultInstance();runtime.executeScript(scripting, filename);// run a Groovy scripting (Groovy V1.1)GroovyShell gs = new GroovyShell();gs.evaluate(scripting);// run a Python scripting (jython V2.2)PythonInterpreter interp = new PythonInterpreter();interp.exec(scripting)
大多数脚本引擎允许为你的脚本捆绑Java环境的主机变量,还可以调用特殊的脚本函数。需要注意的是一些脚本引擎需要额外的设置才可以使用扩展特征。如想要调用gems,就需要设置系统属性(jruby.home和jruby.lib)。
随着Java SE 6的发布,一个标准的host脚本引擎的接口被定制成为Java runtime的一个主要部分。JSR 223:在Java平台上使用脚本中有标准化函数,如:脚本引擎发现,捆绑Java主机变量,和脚本符号。JSR 223接口需要一个JSR 223兼容的脚本实现。主要脚本语言的实现可以从脚本工程主页上下载到。
从脚本中调用Java类
在脚本中引用Java类需要在使用前引入(import)Java类。例如,JRuby定义了一个特殊语句“include Java”来访问Java runtime中内置的Java类。其他非绑定的类引用时需要加前缀“Java ::”,可以参看列表7,JRuby脚本的前几条语句激活了Java支持,定义了常量来代表SSLContext类和BlockingConnection类的路径。
与JRuby相比,脚本runtimes如Jython使用现有的、本身的脚本语句来引入Java类。如Python模块,可以使用普通的Python语句“import&packagename&”引入Java包。Jython还支持Python的不同形式的import语句,如“from &packagename& import &class&”。Groovy,是明确地被设计成运行在Java平台的,它使用Java的import语法。
紧凑的语法意味着代码量的减少
脚本语言的语法要比Java的语法紧凑的多。如,不管是Groovy,Ruby还是Python,都不需要你写冗长的getters和setters(属性设置)。为了简化JavaBeans属性操作,这些脚本语言的Java runtime允许用直接的、类似脚本的方式使用这些属性。
一个Java方法,如&object&.getDefault()可以被写成&object&.default。而且,JRuby runtime会自动把Java的CamelCase(骆驼拼写法)的命名形式匹配为Ruby的形式。如,你可能会这样写一个Java方法:&object&.activateSecureMode(),在JRuby中就变成了&object&.activate_secured_node()。
基于这样的特征,Java类看起来就像是普通的脚本类,参看列表7。这个例子是在Jruby中使用Java的网络类库来实现一个SMTP客户端。
列表7:在JRuby中使用Java类库(实现一个SMTP客户端)
include Java# set up constants to shorten the pathsSSLContext = javax.net.ssl.SSLContextBlockingConnection = Java::org.xsocket.stream.BlockingConnection#performs new BlockingConnection(String, int, SSLContext.getDefault(), boolean)bc = BlockingConnection.new('smtp.web.de', 25, SSLContext::default, false)
bc.receive_timeout_millis = 60 * 1000 # performs setReceiveTimeoutMillis(long)puts bc.read_string_by_delimiter("\r\n")
# performs readStringByDelimiter(String)bc.write("STARTTLS\r\n")
puts bc.read_string_by_delimiter("\r\n")bc.activate_secured_mode()bc.write('AUTH PLAIN ' + ["\000" + 'from.me' + "\000" + 'myPassword'].pack('m'))puts bc.read_string_by_delimiter("\r\n")bc.write("HELO Server\r\n")puts bc.read_string_by_delimiter("\r\n")bc.write("MAIL FROM: ")puts bc.read_string_by_delimiter("\r\n")bc.write("RCPT TO: ")puts bc.read_string_by_delimiter("\r\n")bc.write("data\r\n")puts bc.read_string_by_delimiter("\r\n")mail ='Message-ID: 46D957AF.2020804Date: Sat, 01 Sep :39 +0200From: User-Agent: my mail clientMIME-Version: 1.0To: Subject: what I have to sayContent-Type: text/ charset=ISO-8859-15; format=flowedContent-Transfer-Encoding: 7bitcombining scripting languages with Java is great'bc.write("#{mail}\r\n.\r\n")puts bc.read_string_by_delimiter("\r\n")bc.write("quit\r\n")puts bc.read_string_by_delimiter("\r\n")bc.close()
在Java虚拟机上运行脚本语言可以让你无缝结合Java代码和脚本。通过调用一个嵌入的Java对象的方法,脚本runtime寻找Java类库的一个恰当的方法特征。通过识别一个匹配的Java方法,runtime执行这个方法调用。针对脚本的参数的数据类型自动转化成适合的Java类型。
调用重载的Java方法
就像前面提到的,动态类型语言不需要类型声明。这样也存在不便之处,一个隐藏的陷阱就是调用重载的Java方法。当调用一个重载的Java方法的时候,脚本runtime需要选择合适的方法。某些情况下,选择的方法实现并不是所期望的,参看下面两个例子。
列表8给出了一个重载的Java类。
列表8:一个重载的Java类
public class NonBlockingConnection
public void write(int i)
System.out.println("writing int " + i);
public void write(long l)
System.out.println("writing long " + l);
列表9给出了Jython如何调用这些重载方法
列表9:使用Juthon调用重载方法
from java.lang import Integerfrom test import NonBlockingConnection# call 1 NonBlockingConnection().write() # call method based on python built-in data type# prints out:# writing long # call 2NonBlockingConnection().write(55)
# call method based on python built-in data type# prints out:# writing long 55# ups, not int?# call 3NonBlockingConnection().write(Integer(55))
# pass over a Java object instead of python data type# prints out:# writing int 55
Jython脚本的Call 2部分并没有完成期望的int类型的Java方法的调用。一个用来确定调用哪个重载方法的比较实用的方法是,在脚本中实例化需要的Java数据类型的对象,用它代替脚本内的类型。当你使用Groovy时,方法重载根本不是问题,因为Groovy同时支持静态和动态类型。
从Java调用脚本类
可以在Java环境中通过使用脚本引擎来执行脚本。这样的脚本引擎同时允许执行专门的脚本方法或是函数。JSR 223定义了一个标准接口“Invokable”来实现这样的方法和功能。可以参看列表10,Ruby脚本的一个专门的函数“write”将被调用。
列表10:调用Ruby脚本的一个专门函数
String rubyScript = "def write(msg) \r\n" +
puts msg \r\n" +
"end \r\n" +
" def anotherFunction() \r\n" +
# do something \r\n" +
"end \r\n";
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
engine.eval(rubyScript);
Invocable inv = (Invocable)
inv.invokeFunction("write", new Object[] { "hello" });
// prints out:
一些脚本环境如Jython还支持一个编译器来产生Java类。这种情况下,一个Jython类可以像一个正常的Java类那样被调用。只是产生的Java类的自身能力是受限制的。
重写重载的Java方法
JRuby和Jython都支持实现Java接口和继承Java类。但是对于大多数流行的脚本语言来说,重写重载的Java方法就带来了一个新问题。怎样定义哪个重载的Java方法应该重写?如Rython2.x或Ruby不支持基于类型特征的方法重载。这需要处理重写的方法的所有重载方法。方法的实现需要对所有重载的方法做参数类型的检测。列表11给出了如何用Jython实现
列表11:使用Jython调用重载方法
from test import NonBlockingConnectionfrom java.lang import Integerfrom java.lang import Longclass ExtendedNonBlockingConnection(NonBlockingConnection):
def write(self, *args):
# the signature to handle?
if len(args) == 1 and isinstance(args[0], Integer):
print 'writing overriden int ' + args[0].toString()
# no, let the super method do the stuff
NonBlockingConnection.write(self, *args)ExtendedNonBlockingConnection().write(Integer(777))# prints out:# writing overridden int 777ExtendedNonBlockingConnection().write(Long(777))# prints out:# writing long 777
因为Groovy还支持静态类型声明,重载的方法可以通过参数类型进行声明,如列表12所示。
列表12:使用Groovy调用重载方法
import test.NonBlockingConnectionclass ExtendedNonBlockingConnection extends NonBlockingConnection {
// overwrite the int method
def write(int i) {
println 'writing overridden int ' + i
}}new ExtendedNonBlockingConnection().write((int) 777)// prints out:// writing overridden int 777new ExtendedNonBlockingConnection().write((long) 777)// prints out:// writing long 777
一个双向的完整的应用程序(SMTP服务器)
Java和脚本语言的紧密结合,通常需要通过脚本元素调用Java类,通过Java类调用脚本元素。因此,应用程序由基于脚本的类和基于Java的类这两部分无缝、双向地结合组成。
列表13给出了一个完整的基于脚本的应用程序,调用了Java类。它是一个用JRuby写的SMTP服务器,使用了一个非阻塞的Java网络类库。
列表13:JRuby写的SMTP服务器
include JavaRandomAccessFile = java.io.RandomAccessFileDataConverter = Java::org.xsocket.DataConverter MultithreadedServer = Java::org.xsocket.stream.MultithreadedServerIConnection = Java::org.xsocket.stream.IConnectionIConnectHandler = Java::org.xsocket.stream.IConnectHandlerIDataHandler = Java::org.xsocket.stream.IDataHandlerclass TestMessageSinkManager
def new_message_sink_channel()
file = java.io.File.create_temp_file('smtptest', 'mail')
return RandomAccessFile.new(file, 'rw').channel
endend class SmtpProtocolHandler
include IConnectHandler
include IDataHandler
def initialize(domain, message_sink_manager)
@domain = domain
@msg_sink_mgr = message_sink_manager
@helo_pattern = Regexp.compile(/HELO.*/, Regexp::IGNORECASE)
@mail_from_pattern = Regexp.compile(/MAIL FROM:.*/, Regexp::IGNORECASE)
@rcpt_to_pattern = Regexp.compile(/RCPT TO:.*/, Regexp::IGNORECASE)
@data_pattern = Regexp.compile(/DATA.*/, Regexp::IGNORECASE)
@quit_pattern = Regexp.compile(/QUIT.*/, Regexp::IGNORECASE)
# new incoming (non blocking) connection
def onConnect(nbc)
nbc.flushmode = IConnection::FlushMode::ASYNC
nbc.attachment = { 'state' =& 'CMD', 'msg_num' =& 0 }
nbc.write("220 } SMTP ready \r\n")
return true
# data received for the (non blocking) connection
def onData(nbc)
case nbc.attachment['state']
# message receiving mode: non-blocking streaming of the msg data
when 'MESSAGE'
# some validations have to be performed by the data sink
delimiter_found = nbc.read_available_by_delimiter("\r\n.\r\n",
nbc.attachment['message_channel'])
if delimiter_found
nbc.attachment['message_channel'].close()
nbc.attachment['state'] = 'CMD'
nbc.write("250 OK #{nbc.get_id()}.#{nbc.attachment['msg_num']} \r\n")
# smtp-command mode: perform command
# a BufferUnderflowException will been thrown, if delimiter not found
smtp_cmd_line = nbc.read_string_by_delimiter("\r\n")
case smtp_cmd_line
when @helo_pattern
nbc.write("250 } SMTP Service \r\n")
when @mail_from_pattern
originator = smtp_cmd_line[10,9999].strip()
# ...here some validations should be performed (valid address, ...)
nbc.attachment['originator'] = originator
nbc.attachment['recipients'] = []
nbc.write("250 } is syntactically correct\r\n")
when @rcpt_to_pattern
rec = smtp_cmd_line[8,9999].strip()
# ...here some validations should be performed (max recipients, ...)
nbc.attachment['recipients'] = nbc.attachment['recipients'] && rec
nbc.write("250 #{rec} verified \r\n")
when @data_pattern
# ...here some validation should be performed (recipients set, ...)
nbc.attachment['state'] = 'MESSAGE'
nbc.attachment['msg_num'] = nbc.attachment['msg_num'] + 1
nbc.attachment['message_channel'] =
@msg_sink_mgr.new_message_sink_channel()
time_stamp = "Received: FROM #{nbc.remote_address.canonical_host_name}
"id #{nbc.get_id()}.#{nbc.attachment['msg_num']};
" + Time.new.to_s() + "\r\n"
nbc.attachment['message_channel'].write(DataConverter.to_byte_buffer(time_stamp,
'US-ASCII'))
nbc.write("354 Enter message, ending with \".\"
when @quit_pattern
nbc.write("221 SMTP service closing connection \r\n")
nbc.close()
nbc.write("500 Unrecognized command \r\n")
return true
endendserver = MultithreadedServer.new(25, SmtpProtocolHandler.new('mSrv',
TestMessageSinkManager.new))server.run()
在这个应用程序中,一个基于Java的服务器被实例化,监听将到来的SMTP网络连接。网络事件由基于JRuby的Handler处理。为了做这件事情,基于JRuby的Handler需要实现一个由Java网络类库定义的Java回调接口。
为了实现这个Java接口,JRuby类需要使用“include &java interface&”语句来声明支持所有接口。与基于Java的接口实现不同,返回类型或异常不需要由基于JRuby的方法实现定义。通过实现handler的一个回调函数,一个Java对象被转换成(以InonBlockingConnection实例)JRuby脚本。
对这个Java对象的访问就会被脚本环境截获到。因此,它可以就像是一个Ruby对象那样,在JRuby方法实现内部处理。原始的数据类型,如Java的Integer或Long都被映射成相应的Ruby类型。
如果一个网络事件发生,服务器完成handler的恰当的回调方法。这个可以工作成功,因为基于Ruby的handler对服务器来说就像是一个规则的Java类。JRuby runtime自动包装这个基于JRuby的handler,把它转化给Java服务器。Java服务器不需要获得本身的JRuby Handler,而是获得一个代理,支持所有由这个Handler实现的Java接口的方法。
基于Java的脚本runtimes努力地把Java平台和你所选择的脚本语言结合在一起。在现在这个早期阶段,脚本runtime引擎有很大不同。在当前的JRuby或Jython的版本中,你可能会发现一些Java平台所没有的新特征,如注释支持。这对于架起Java语言和脚本语言之间的语义桥梁来说,同样是一种挑战,有些时候需要一些并不好看的解决方案。这就是说,大多数情况下,那些支持的特征对于使用Java平台,Java代码,脚本语言来写一个企业层应用程序来说,也是足够了。
在列表13中提到的那个双向、完整的应用程序例子是一个非阻塞的,多线程的SMTP服务器,是使用脚本语言类和Java类共同写成的。使用一个现有的Java网络类库处理低水平的、性能重要的、网络明确的任务,如线程或连接管理。控制任务通过脚本语言实现。显现出来的Java平台和脚本语言之间的协和作用使得写出高性能、可升级的应用程序成为了一种可能。所面临的挑战是如何为恰当的任务选择恰当的语言。
在脚本方面,你可以选择现有的语言,如JRuby或Jython,和一个适用于运行在Java平台上的脚本语言,如Groovy。第一组使得Java类看起来像是有规则的脚本。Groovy使用一个与Java代码很相似的语法,但是它更进化,每一个Groovy类是一个丰满的Java类。Groovy与其他脚本语言相比,对Java开发者来说更简单,它可以完全无缝地使用Java类库,不需要任何中转。
想要学习更多的关于在Java平台上使用脚本的方法,或是了解“polyglot”编程,或是对这篇文章中提到的语言感兴趣,可以参看资源部分
Gregor Roth是一个软件架构师,工作于United Internet组,这是一个欧洲Internet服务提供商。他所感兴趣的领域包括:软件和系统结构,企业结构管理,面向对象设计,分布式计算,开发方法,当然还包括Java。他的职业生涯是开始于C和基于汇编的微型控制器应用软件。1997年,他开始设计和开发大型的、基于Java的分布式企业系统。
原文链接:
【相关文章】
【责任编辑: TEL:(010)】

我要回帖

更多关于 java 静态和动态 的文章

 

随机推荐