程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java.next:第二部分——與Java的互操作

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

編輯:關於JAVA

本文是Java.next系列的第二部分。在這一部分,我們來看Java.next語言如何與Java進行互操作。

在所有這些Java.next語言中,與Java互操作都是很簡單的一件事。這得歸功於Java虛擬機規范,它使得JVM上的其它語言能夠很容易的反射以及調用Java代碼。

一個Swing的例子

作為與Java互操作的第一個例子,考慮通過調用Swing API創建一個應用程序,使其包含:

● 一個窗口

● 一個按鈕

● 點擊按鈕時彈出一個模式對話框

作為參照,這裡先給出使用原始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應用。對於這些代碼,有兩點需要注意的地方:

■ 在這個例子中,我根據這些語言與Java語法差異從小到大的順序呈現代碼。這樣做使得我們能從熟悉東西自然過渡到陌生的事物。

■ 下面這些實現並不是這些語言的最佳實踐。它們被刻意簡化,使得我們能將注意力集中在與Java的互操作上。在接下來的文章中,我將更多的展現這些語言的習慣用法。

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版本使得我們能夠忽略:

◇ 分號

◇ 類型聲明

◇ 大部分括號

◇ 屬性的Getter與Setter

Groovy版本的最大優勢體現在事件監聽器上,它展現了:

◇ 多行字符串(使用"""界定)

◇ 使用${}往字符串裡插入it.actionCommand

◇ 不需要匿名內部類,簡單的傳遞一個匿名函數

在SwingBuilder項目中可以看到如何用更符合Groovy習慣用法去使用Swing。

我們可以得出一個顯而易見的結論:在Groovy中與Java互操作相當簡單。

Scala的實現

接下來,讓我們看看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具有許多相同的優點:

◇ 更少的類型聲明

◇ 更少的分號

◇ 更少的括號

我們還可以看到Scala獨有的一些性質:

◇ 在Scala中import通配符是_而不是熟悉的*。*號具有其它意義

◇ Scala能夠單行引入同一個package中的多個class

◇ 因為我們只需要一個實例,所以我們用object聲明而不是class

◇ 該object繼承了JFrame,Scala允許我們使用內嵌的方式調用JFrame的構造函數,而不必再單獨聲明一個構造函數

與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的項目。使用這些庫,你能夠書寫更加簡潔的代碼。作為示例,你可以參看ScalaGUI。

JRuby的實現

現在來看看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的代碼進行對比,你會發現它們幾乎具有相同的特點:

◇ 更少的類型聲明

◇ 更少的分號

◇ 更少的括號

◇ 簡潔的屬性訪問(沒有getter與setter)

◇ 多行字符串(使用END界定)

◇ 使用${}往字符串裡插入it.actionCommand

相比而言,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交互,可以參看JRUBY-903以了解相關歷史。如果想了解更符合JRuby習慣用法的Swing使用方式,可以看Profligacy項目。

結論:在JRuby中,與Java互操作很簡單。

Clojure的實現

這兒是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互操作很簡單。

結論

在上面的例子中,我演示了Java.next可以方便的與Java互操作。每一個例子都使用了比Java更少的代碼來操作Swing庫。更重要的是,Java.next的版本抓住了問題的本質並簡化了形式。

與Java的無縫銜接並不是衡量Java.next語言的首要標准,因為它們都做得很好。這裡並沒有體現出這些語言在復雜情形下的表現,但我認為它們與Java互操作的問題已經得到了根本的解決。

Java.next系列的前兩篇文章中,我采用了接近Java語言的風格來展示Java.next語言的特性。有了這些基礎,是時候去使用Java.next各自的習慣用法了。在本系列文章接下來的部分,我們將會看到Java.next語言如何支持領域特定語言。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved