## Java 互操作
Clojure程序可以使用所有的java類以及接口。和在java里面一樣 `java.lang` 這個包里面的類是默認導入的。你可以手動的用 `import` 函數來導入其它包的類。看例子:
```
(import
'(java.util Calendar GregorianCalendar)
'(javax.swing JFrame JLabel))
```
同時也可以看下宏ns下面的 `[:import](http://xumingming.sinaapp.com/302/clojure-functional-programming-for-the-jvm-clojure-tutorial/#nsMacro) 指令, 我們會在后面介紹的。`
有兩種方式可以訪問類里面的常量的:
```
(. java.util.Calendar APRIL) ; -> 3
(. Calendar APRIL) ; works if the Calendar class was imported
java.util.Calendar/APRIL
Calendar/APRIL ; works if the Calendar class was imported
```
在Clojure代碼里面調用java的方法是很簡單的。因此很多java里面已經實現的功能Clojure就沒有實現自己的了。比如, Clojure里面沒有提供函數來計算一個數的絕對值,因為可以用 `java.lang.Math` 里面的abs方法。而另一方面,比如這個類里面還提供了一個 `max` 方法來計算兩個數里面比較大的一個, 但是它只接受兩個參數,因此Clojure里面自己提供了一個可以接受多個參數的max函數。
有兩種方法可以調用java里面的靜態方法:
```
(. Math pow 2 4) ; -> 16.0
(Math/pow 2 4)
```
同樣也有兩種方法來創建一個新的java的對象,看下面的例子。這里注意一下我們用 `def` 創建的對象bind到一個全局的binding。這個其實不是必須的。有好幾種方式可以得到一個對象的引用比如把它加入一個集合或者把它傳入一個函數。
```
(import '(java.util Calendar GregorianCalendar))
(def calendar (new GregorianCalendar 2008 Calendar/APRIL 16)) ; April 16, 2008
(def calendar (GregorianCalendar. 2008 Calendar/APRIL 16))
```
同樣也有兩種方法可以調用java對象的方法:
```
(. calendar add Calendar/MONTH 2)
(. calendar get Calendar/MONTH) ; -> 5
(.add calendar Calendar/MONTH 2)
(.get calendar Calendar/MONTH) ; -> 7
```
一般來說我們比較推薦使用下面那種用法(.add, .get), 上面那種用法在定義宏的時候用得比較多, 這個等到我們講到宏的時候再做詳細介紹。
方法調用可以用 `..` 宏串起來:
```
(. (. calendar getTimeZone) getDisplayName) ; long way
(.. calendar getTimeZone getDisplayName) ; -> "Central Standard Time"
```
還一個宏: `.?.` 在 `clojure.contrib.core` 名字空間里面, 它和上面..這個宏的區別是,在調用的過程中如果有一個返回結果是nil, 它就不再繼續調用了,可以防止出現 `NullPointerException` 異常。
`doto` 函數可以用來調用一個對象上的多個方法。它返回它的第一個參數, 也就是所要調用方法的對象。這對于初始化一個對象的對各屬性是非常方便的。 (看下面”Namespaces“那一節的 `JFrame` GUI 對象的例子). 比如:
```
(doto calendar
(.set Calendar/YEAR 1981)
(.set Calendar/MONTH Calendar/AUGUST)
(.set Calendar/DATE 1))
(def formatter (java.text.DateFormat/getDateInstance))
(.format formatter (.getTime calendar)) ; -> "Aug 1, 1981"
```
`memfn` 宏可以自動生成代碼以使得java方法可以當成clojure里面的“一等公民”來對待。這個可以用來替代clojure里面的匿名方法。當用 `memfn` 來調用java里面那些需要參數的方法的時候, 你必須給每個參數指定一個名字,以讓clojure知道你要調用的方法需要幾個參數。這些名字到底是什么不重要,但是它們必須要是唯一的, 因為要用這些名字來生成Clojure代碼的。下面的代碼用了一個map方法來從第二個集合里面取beginIndex來作為參數調用第一個集合里面的字符串的substring方法。大家可以看一下用匿名函數和用memfn來直接調用java的方法的區別。
```
(println (map #(.substring %1 %2)
["Moe" "Larry" "Curly"] [1 2 3])) ; -> (oe rry ly)
(println (map (memfn substring beginIndex)
["Moe" "Larry" "Curly"] [1 2 3])) ; -> same
```