Java.next:第二部分——与Java互操作

  [color=blue]原文地址[/color]:[url=http://blog.thinkrelevance.com/2008/8/12/java-next-2-java-interop]Java.next #2: Java Interop[/url]
  [color=blue]翻  译[/color]:[url=http://eastsun.iteye.com]Eastsun[/url]
  本文是Java.next系列的第二部分。在这一部分,我们来看Java.next语言如何与Java进行互操作。
  在所有这些Java.next语言中,与Java互操作都是很简单的一件事。这得归功于Java虚拟机规范,它使得JVM上的其它语言能够很容易的反射以及调用Java代码。

[color=darkblue][b][size=medium]一个Swing的例子[/size][/b][/color]
  作为与Java互操作的第一个例子,考虑通过调用Swing API创建一个应用程序,使其包含:
  [color=green]● 一个窗口
  ● 一个按钮
  ● 点击按钮时弹出一个模式对话框[/color]

  作为参照,这里先给出使用原始Java代码给出的实现:
// Java
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class Swing {
public static void main(String[] args) {
JFrame frame = new JFrame("Hello Swing");
JButton button = new JButton("Click Me");

button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
JOptionPane.showMessageDialog(null,
String.format("<html>Hello from <b>Java</b><br/>" +
"Button %s pressed", event.getActionCommand()));
}
});
frame.getContentPane().add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}

  接下来,我将使用Java.next中的语言来实现这个Swing应用。对于这些代码,有两点需要注意的地方:
  [color=orange]■ 在这个例子中,我根据这些语言与Java语法差异从小到大的顺序呈现代码。这样做使得我们能从熟悉东西自然过渡到陌生的事物。
  ■ 下面这些实现并不是这些语言的最佳实践。它们被刻意简化,使得我们能将注意力集中在与Java的互操作上。在接下来的文章中,我将更多的展现这些语言的习惯用法。[/color]

Groovy的实现
  Groovy是Java.next语言中与Java最相似的,下面是Groovy的实现代码:
// Groovy
import javax.swing.JFrame
import javax.swing.JButton
import javax.swing.JOptionPane
import java.awt.event.ActionListener

frame = new JFrame("Hello Swing")
button = new JButton("Click Me")

button.addActionListener({
JOptionPane.showMessageDialog(null, """<html>Hello from <b>Groovy</b>
Button ${it.actionCommand} pressed""")
} as ActionListener)
frame.contentPane.add button

frame.defaultCloseOperation = JFrame.EXIT_ON_CLOSE
frame.pack()
frame.visible = true

  与Java的实现对比一下可以发现,它们几乎一样。只不过省略了一些冗余的代码结构。Groovy版本使得我们能够忽略:
  [color=orange]◇ 分号
  ◇ 类型声明
  ◇ 大部分括号
  ◇ 属性的Getter与Setter[/color]

  Groovy版本的最大优势体现在事件监听器上,它展现了:
  [color=orange]◇ 多行字符串(使用"""界定)
  ◇ 使用${}往字符串里插入it.actionCommand
  ◇ 不需要匿名内部类,简单的传递一个匿名函数[/color]

  在[url=http://groovy.codehaus.org/Swing+Builder]SwingBuilder[/url]项目中可以看到如何用更符合Groovy习惯用法去使用Swing。
  我们可以得出一个显而易见的结论:在Groovy中与Java互操作相当简单。

[color=darkblue][b][size=medium]Scala的实现[/size][/b][/color]
  接下来,让我们看看Scala的版本:
// Scala (almost right, see below)
import javax.swing._
import java.awt.event.{ActionEvent, ActionListener}

object HelloWorld extends JFrame("Hello Swing") {
def showButtonMessage(msg: String) =
JOptionPane.showMessageDialog(null, String.format("""<html>Hello from <b>Scala</b>. Button %s pressed""", Array(msg)));

def main(args: Array[String]) {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
val button = new JButton("Click Me")
button.addActionListener((e:ActionEvent) => showButtonMessage(e.getActionCommand.toString))
getContentPane add button
pack
setVisible(true)
}
}

  Scala版本与Groovy相对Java具有许多相同的优点:
  [color=orange]◇ 更少的类型声明
  ◇ 更少的分号
  ◇ 更少的括号[/color]

  我们还可以看到Scala独有的一些性质:
  [color=orange]◇ 在Scala中import通配符是_而不是熟悉的*。*号具有其它意义
  ◇ Scala能够单行引入同一个package中的多个class
  ◇ 因为我们只需要一个实例,所以我们用object声明而不是class
  ◇ 该object继承了JFrame,Scala允许我们使用内嵌的方式调用JFrame的构造函数,而不必再单独声明一个构造函数[/color]

  与Groovy一样,最大的不同是事件监听器。Scala同样允许我们简单的传入一个匿名函数,而不需要使用匿名内部类。
button.addActionListener((e:ActionEvent) => 
showButtonMessage(e.getActionCommand.toString))

  看起来很强大,只不过这儿我做了一个小小的弊。Scala是强类型语言,它不会自动将一个函数类型转换为一个ActionListener。因此上面的代码还不能被编译通过。幸运的是,Scala的隐式转换功能让我们拥有这个能力:强类型加上一个便利的类型系统。所有我们要做的是告诉Scala这个转换是合法的:

// Yes, we can
implicit def actionPerformedWrapper(func: (ActionEvent) => Unit) =
new ActionListener { def actionPerformed(e:ActionEvent) = func(e) }

  将上面的代码放到适当的位置,我们就能够在需要ActionListener的地方传入一个函数。
  已经有多个将Swing包装为Scala的项目。使用这些库,你能够书写更加简洁的代码。作为示例,你可以参看[url=http://scala.sygneca.com/code/scalagui]ScalaGUI[/url]。

[color=darkblue][b][size=medium]JRuby的实现[/size][/b][/color]
  现在来看看JRuby的情形:
include Java
import javax.swing.JFrame
import javax.swing.JButton
import javax.swing.JOptionPane
import java.awt.event.ActionListener

button = JButton.new "Click Me"
button.add_action_listener do |evt|
JOptionPane.showMessageDialog(nil, <<-END)
<html>Hello from <b>JRuby</b>.
Button '#{evt.getActionCommand()}' clicked.
END
end

frame = JFrame.new "Hello Swing"
frame.content_pane.add button
frame.default_close_operation = JFrame::EXIT_ON_CLOSE
frame.pack
frame.visible = true


  如果与之前Groovy的代码进行对比,你会发现它们几乎具有相同的特点:
  [color=orange]◇ 更少的类型声明
  ◇ 更少的分号
  ◇ 更少的括号
  ◇ 简洁的属性访问(没有getter与setter)
  ◇ 多行字符串(使用END界定)
  ◇ 使用${}往字符串里插入it.actionCommand[/color]

  相比而言,JRuby的ActionListener实现比Groovy稍微简单一点。JRuby能够自动根据block生成ActionListener:
button.add_action_listener { |evt|
# do stuff
}


  在JRuby的例子中,我依照Ruby的命名方式来使用Java方法名:
# Ruby
frame.content_pane

  Java程序员习惯Camel命名方式。为了便利,JRuby同时支持这两种命名方式:
# Groovy, Scala, or JRuby
frame.contentPane

  由于Ruby语言的灵活性,鼓励试验不同的语法与Java交互,可以参看[url=http://jira.codehaus.org/browse/JRUBY-903]JRUBY-903[/url]以了解相关历史。如果想了解更符合JRuby习惯用法的Swing使用方式,可以看[url=http://ihate.rubyforge.org/profligacy]Profligacy [/url]项目。
  结论:在JRuby中,与Java互操作很简单。

[color=darkblue][b][size=medium]Clojure的实现[/size][/b][/color]
  这儿是Clojure的版本:
; Clojure 
; Clojure
(import '(javax.swing JFrame JButton JOptionPane))
(import '(java.awt.event ActionListener))

(let [frame (JFrame. "Hello Swing")
button (JButton. "Click Me")]
(.addActionListener button
(proxy [ActionListener] []
(actionPerformed [evt]
(JOptionPane/showMessageDialog nil,
(str "<html>Hello from <b>Clojure</b>. Button "
(.getActionCommand evt) " clicked.")))))

(.. frame getContentPane (add button))
(doto frame
(setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
pack
(setVisible true)))

  Clojure是一种Lisp方言,因此其语法与其它几种有着本质上的不同。这一点就得花上几个小时来讨论,但我们现在的焦点是与Java的互操作,所以我将这一点留给这系列以后文章来讨论。现在,让我们把注意力放到与Java互操作上来。
  导入Java类是件很容易的事。import之后跟着一串参数,第一项是package,其余的是要导入到当前名字空间的class。注意,这样允许我们在一行中导入多个class。
(import '(javax.swing JFrame JButton JOptionPane))

  创建一个Java实例也很简单,使用(class. &args)的形式:
(JFrame. "Hello Swing")

  有多种途径来调用Java类中的方法。你可以使用(.methodName obj &args)的方式来调用单个方法。对于静态方法,使用(class/method &args)的方式:
(JOptionPane/showMessageDialog nil "A message")

  在Java中,可以通过x.y().z()的方式使用链式调用。在Clojure中你可以使用(.. x (y) (z))的方式:
(.. frame (getContentPane) (add button))

  最后的三个方法调用都是在frame对象上。使用Clojure的doto,你能够在一个对象上执行多次操作并避免每次都要重写这个对象:
(doto frame
(setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
pack
(setVisible true)))

  与其它几个例子一样,事件监听器是最有趣的部分。在Clojure中,proxy能够动态创建Java实例,并允许你实现所需的接口与方法。
(proxy [ActionListener] []
(actionPerformed [evt] {do stuff here...}))

  同JRuby一样,相对Groovy这个解决方案更具有普适性,同时需要使用更多的语法。同样,你能够构建自己的语法结构。
  结论:在Clojure中与Java互操作很简单。

[color=darkblue][b][size=medium]结论[/size][/b][/color]
  在上面的例子中,我演示了Java.next可以方便的与Java互操作。每一个例子都使用了比Java更少的代码来操作Swing库。更重要的是,Java.next的版本抓住了问题的本质并简化了形式。
  与Java的无缝衔接并不是衡量Java.next语言的首要标准,因为它们都做得很好。这里并没有体现出这些语言在复杂情形下的表现,但我认为它们与Java互操作的问题已经得到了根本的解决。
  Java.next系列的前两篇文章中,我采用了接近Java语言的风格来展示Java.next语言的特性。有了这些基础,是时候去使用Java.next各自的习惯用法了。在本系列文章接下来的部分,我们将会看到Java.next语言如何支持领域特定语言。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值