欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入學習java中的Groovy 和 Scala 類

 更新時間:2019年06月12日 10:10:32   作者:Neal Ford  
本文將探討三種下一代 JVM 語言:Groovy、Scala 和 Clojure,比較并對比新的功能和范例,讓 Java 開發(fā)人員對自己近期的未來發(fā)展有大體的認識。,需要的朋友可以參考下

前言

Java 傳承的是平臺,而不是語言。有超過 200 種語言可以在 JVM 上運行,它們之中不可避免地會有一種語言最終將取代 Java 語言,成為編寫 JVM 程序的最佳方式。本系列將探討三種下一代 JVM 語言:Groovy、Scala 和 Clojure,比較并對比新的功能和范例,讓 Java 開發(fā)人員對自己近期的未來發(fā)展有大體的認識。

Java 語言的開發(fā)人員精通 C++ 和其他語言,包括多繼承(multiple inheritance),使得類可以繼承自任意數(shù)量的父類。多繼承帶來的一個問題是,不可能確定所繼承的功能來自哪個父類。這個問題被稱為鉆石問題(請參閱 參考資料)。鉆石問題和多繼承中固有的其他復雜性啟發(fā)了 Java 語言設計者選擇 “單繼承加接口” 的方法。

接口定義了語義,但沒有定義行為。它們非常適合用來定義方法簽名和數(shù)據(jù)抽象,所有 Java 下一代語言都支持 Java 接口,并且無需進行重大的修改。不過,有些交叉問題不適合使用 “單繼承加接口” 模型。這種錯位導致必須提供適合 Java 語言的外部機制,比如面向方面的編程。兩種 Java 下一代語言(Groovy 和 Scala)通過使用一種被稱為混入 或特征 的語言結(jié)構(gòu)在另一個層次的擴展上處理這類問題。本文介紹了 Groovy 中的混入和 Scala 中的特征,并演示了如何使用它們。(Clojure 通過協(xié)議處理大致相同的功能,我在 Java 下一代:沒有繼承性的擴展,第 2 部分 中已經(jīng)介紹過這一點。)

混入

混入的概念起源于 Flavors 語言(請參閱 參考資料)。這個概念的靈感來自于開發(fā)該語言的辦公室附近的一家冰​​淇淋店。這家冰淇淋店提供了純口味的冰淇淋,以及客戶想要的其他任何的 “混合物”(糖果碎、糖屑、堅果,等等)。

早期的一些面向?qū)ο笳Z言在單個代碼塊中共同定義某個類的屬性和方法,所有類定義是完整的。在其他語言中,開發(fā)人員可以在一個地方定義屬性,但推遲方法的定義,并在適當?shù)臅r候?qū)⑺鼈?“混合” 到類中。隨著面向?qū)ο笳Z言的演變,混入與現(xiàn)代語言的配合方式的細節(jié)也在演變。

在 Ruby、Groovy 和類似的語言中,作為一個接口和父類之間的交叉,混入可以擴充現(xiàn)有的類層次結(jié)構(gòu)。像接口一樣,混入可以充當 instanceof 檢查的類型,同時也要遵循相同的擴展規(guī)則。您可以將無限數(shù)量的混入應用于某一個類。與接口不同的是,混入不僅指定了方法簽名,也可以實現(xiàn)簽名的行為。

在包括混入的第一種語言中,混入只包含方法,不包含狀態(tài),例如,成員變量?,F(xiàn)在很多語言(Groovy 也在其中)都包括有狀態(tài)的混入。Scala 的特征也以有狀態(tài)的方式進行操作。

Groovy 的混入

Groovy 通過 metaClass.mixin() 方法或 @Mixin 注解來實現(xiàn)混入。(@Mixin 注解依次使用 Groovy Abstract Syntax Tree (AST) 轉(zhuǎn)換,以支持所需的元編程管道。)清單 1 中的示例使用 metaClass.mixin() 讓 File 類能夠創(chuàng)建 ZIP 壓縮文件:

清單 1. 將 zip() 方法混合到 File 類中

class Zipper {
def zip(dest) {
new ZipOutputStream(new FileOutputStream(dest))
.withStream { ZipOutputStream zos ->
eachFileRecurse { f ->
if (!f.isDirectory()) {
zos.putNextEntry(new ZipEntry(f.getPath()))
new FileInputStream(f).withStream { s ->
zos << s
zos.closeEntry()
}
}
}
}
}
static {
File.metaClass.mixin(Zipper)
}
}

在清單 1 中,我創(chuàng)建了一個 Zipper 類,它包含新的 zip() 方法,以及將該方法添加到現(xiàn)有 File 類的連接。zip() 方法的(不起眼的)Groovy 代碼以遞歸方式創(chuàng)建了一個 ZIP 文件。清單的最后一部分通過使用靜態(tài)的初始化程序,將新方法添加到現(xiàn)有的 File 類。在 Java 語言中,類的靜態(tài)初始化程序在加載類的時候運行。靜態(tài)初始化程序是擴充代碼的理想位置,因為在運行依賴于增強的任何代碼之前,應確保先運行初始化程序。在 清單 1 中,mixin() 方法將 zip() 方法添加到 File。

在 "沒有繼承性的擴展,第 1 部分" 中,我介紹了兩種 Groovy 機制: ExpandoMetaClass 和類別類,您可以使用它們在現(xiàn)有類上添加、更改或刪除方法。使用 mixin() 添加方法的最終結(jié)果與使用 ExpandoMetaClass 或類別類添加方法的最終結(jié)果相同,但它們的實現(xiàn)是不一樣的。請考慮清單 2 中混入示例:

清單 2. 混入操縱繼承層次結(jié)構(gòu)

import groovy.transform.ToString
class DebugInfo {
def getWhoAmI() {
println "${this.class} <- ${super.class.name} 
<<-- ${this.getClass().getSuperclass().name}"
}
}
@ToString class Person {
def name, age
}
@ToString class Employee extends Person {
def id, role
}
@ToString class Manager extends Employee {
def suiteNo
}
Person.mixin(DebugInfo)
def p = new Person(name:"Pete", age:33)
def e = new Employee(name:"Fred", age:25, id:"FRE", role:"Manager")
def m = new Manager(name:"Burns", id:"001", suiteNo:"1A")
p.whoAmI
e.whoAmI
m.whoAmI

在清單 2 中,我創(chuàng)建了一個名為 DebugInfo 的類,其中包含一個 getWhoAmI 屬性定義。在該屬性內(nèi),我打印出類的一些詳細信息,比如當前類以及 super 和 getClass().getSuperClass() 屬性的父子關系說明。接下來,我創(chuàng)建一個簡單的類層次結(jié)構(gòu),包括 Person、Employee 和 Manager。

然后我將 DebugInfo 類混合到駐留在層次結(jié)構(gòu)頂部的 Person 類。由于 Person 具有 whoAmI 屬性,所以其子類也具有該屬性。

在輸出中,可以看到(并且可能會感到驚訝),DebugInfo 類將自己插入到繼承層次結(jié)構(gòu)中:

class Person <- DebugInfo <<-- java.lang.Object
class Employee <- DebugInfo <<-- Person
class Manager <- DebugInfo <<-- Employee

混入方法必須適應 Groovy 中現(xiàn)有的復雜關系,以便進行方法解析。清單 2 中的父類的不同返回值反映了這些關系。方法解析的細節(jié)不屬于本文的討論范圍。但請小心處理對混入方法中的 this 和 super 值(及其各種形式)的依賴。

使用類別類或 ExpandoMetaClass 不影響繼承,因為您只是對類進行修改,而不是混入不同的新行為中。這樣做的一個缺點是,無法將這些更改識別為一個不同類別的構(gòu)件。如果我使用類別類或 ExpandoMetaClass 將相同的三個方法添加到多個類中,那么沒有特定的代碼構(gòu)件(比如接口或類簽名)可以識別目前存在的共性。混入的優(yōu)點是,Groovy 將使用混入的一切都視為一個類別。

類別類實現(xiàn)的一個麻煩之處在于嚴格的類結(jié)構(gòu)。您必須完全使用靜態(tài)方法,每個方法至少需要接受一個參數(shù),以代表正在進行擴充的類型。元編程是最有用的,它可以消除這樣的樣板代碼。@Mixin 注釋的出現(xiàn)使得創(chuàng)建類別并將它們混合到類中變得更容易。清單 3(摘自 Groovy 文檔)說明了類別和混入之間的協(xié)同效應:

清單 3. 結(jié)合類別和混入

interface Vehicle {
String getName()
}
@Category(Vehicle) class Flying {
def fly() { "I'm the ${name} and I fly!"}
}
@Category(Vehicle) class Diving {
def dive() { "I'm the ${name} and I dive!"}
}
@Mixin([Diving, Flying])
class JamesBondVehicle implements Vehicle {
String getName() { "James Bond's vehicle" }
}
assert new JamesBondVehicle().fly() ==
"I'm the James Bond's vehicle and I fly!"
assert new JamesBondVehicle().dive() ==
"I'm the James Bond's vehicle and I dive!"

在清單 3 中,我創(chuàng)建了一個簡單的 Vehicle 接口和兩個類別類(Flying 和 Diving)。@Category 注釋關注樣板代碼的要求。在定義了類別之后,我將它們混合成一個 JamesBondVehicle,以便連接兩個行為。

類別、ExpandoMetaClass 和混入在 Groovy 中的交集是積極的語言進化的必然結(jié)果。三種技術明顯有重疊之處,但每種技術都有它們自身才能處理得最好的強項。如果從頭重新設計 Groovy,那么作者可能會將三種技術的多個特性整合在一個機制中。

Scala 的特征

Scala 通過特征 實現(xiàn)了代碼重用,這是類似于混入的一個核心語言特性。Scala 中的特征是有狀態(tài)的(它們可以同時包括方法和字段),它們與 Java 語言中的接口扮演相同的 instanceof 角色。特征和混入解決了多個相同的問題,但特征在語言嚴謹性方面獲得了更多的支持。

In "Groovy、Scala 和 Clojure 中的共同點,第 1 部分" 中,我使用了一個復數(shù)類來說明 Scala 中的操作符重載。我沒有在該類中實現(xiàn)布爾比較操作符,因為 Scala 內(nèi)置的 Ordered 特征使得實現(xiàn)變得微不足道。清單 4 顯示了改進的復數(shù)類,它利用了 Ordered 特征的優(yōu)勢:

清單 4. 比較復數(shù)

final class Complex(val real:Int, val imaginary:Int) extends Ordered[Complex] {
require (real != 0 || imaginary != 0)
def +(operand:Complex) =
new Complex(real + operand.real, imaginary + operand.imaginary)
def +(operand:Int) =
new Complex(real + operand, imaginary)
def -(operand:Complex) =
new Complex(real - operand.real, imaginary - operand.imaginary)
def -(operand:Int) =
new Complex(real - operand, imaginary)
def *(operand:Complex) =
new Complex(real * operand.real - imaginary * operand.imaginary,
real * operand.imaginary + imaginary * operand.real)
override def toString() =
real + (if (imaginary < 0) "" else "+") + imaginary + "i"
override def equals(that:Any) = that match {
case other :Complex => (real == other.real) && (imaginary == other.imaginary)
case _ => false
}
override def hashCode():Int =
41 * ((41 + real) + imaginary)
def compare(that:Complex) :Int = {
def myMagnitude = Math.sqrt(this.real ^ 2 + this.imaginary ^ 2)
def thatMagnitude = Math.sqrt(that.real ^ 2 + that.imaginary ^ 2)
(myMagnitude - thatMagnitude).round.toInt
}
}

我在清單 4 中沒有實現(xiàn) >、<、<= 和 >= 運算符,但我可以在復數(shù)實例中調(diào)用它們,如清單 5 所示:

清單 5. 測試比較

class ComplexTest extends FunSuite {
test("comparison") {
assert(new Complex(1, 2) >= new Complex(3, 4))
assert(new Complex(1, 1) < new Complex(2,2))
assert(new Complex(-10, -10) > new Complex(1, 1))
assert(new Complex(1, 2) >= new Complex(1, 2))
assert(new Complex(1, 2) <= new Complex(1, 2))
}
}

因為不需要采用數(shù)學上定義的技術來比較復數(shù),所以在 清單 4 中,我使用了一個被人們普遍接受的算法來比較數(shù)字的大小。我使用 Ordered[Complex] 特征來 extend 類定義,它混入了參數(shù)化的類的布爾運算符。為了讓特征可以正常工作,注入的運算符必須比較兩個復數(shù),這是 compare() 方法的目的。如果您嘗試 extendOrdered 特征,但不提供所需的方法,那么編譯器消息會通知您,因為缺少所需的方法,所以必須將您的類聲明為 abstract。

在 Scala 中,特征有兩個明確定義的作用:豐富接口和執(zhí)行可堆疊的修改。

豐富接口

在設計接口時,Java 開發(fā)人員面臨著一個取決于便利性的難題:應該創(chuàng)建包含很多方法的富 接口,還是創(chuàng)建只有幾個方法的瘦 接口?富接口對于其消費者更方便一些,因為它提供了廣泛的方法調(diào)色板,但方法的絕對數(shù)量使得接口更加難以實現(xiàn)。瘦接口的問題剛好相反。

特征可以解決使用富接口還是薄接口的這種兩難問題。您可以在瘦接口中創(chuàng)建核心功能,然后使用特征擴充它,以提供更豐富的功能。例如,在 Scala 中,Set 特征實現(xiàn)了一個設置好的共享功能,您選擇的子特征( mutable 或 immutable)已經(jīng)決定了設置是否可變。

可堆疊的修改

Scala 中的特征的另一個常見用途是可堆疊的修改。利用特征,您可以修改現(xiàn)有的方法并添加新的方法,super 提供了對可以鏈接回以前的特征實現(xiàn)的訪問。

清單 6 通過一些隊列說明了可堆疊的修改:

清單 6. 構(gòu)建可堆疊的修改

abstract class IntQueue {
def get():Int
def put(x:Int)
}
import scala.collection.mutable.ArrayBuffer
class BasicIntQueue extends IntQueue {
private val buf = new ArrayBuffer[Int]
def get() = buf.remove(0)
def put(x:Int) { buf += x }
}
trait Squaring extends IntQueue {
abstract override def put(x:Int) { super.put(x * x) }
}

在清單 6 中,我創(chuàng)建一個簡單的 IntQueue 類。然后,我構(gòu)建一個可變的版本,該版本中包括 ArrayBuffer。Squaring 特征擴展了所有 IntQueue,并在值被插入隊列中時自動對其進行平方計算。在 Squaring 特征內(nèi)對 super 的調(diào)用提供對堆棧中前面的特性的訪問。除了第一個方法之外,只要每個被重寫的方法調(diào)用 super,修改堆棧就會一個一個地堆疊上去,如清單 7 所示:

清單 7. 構(gòu)建堆疊的實例

object Test {
def main(args:Array[String]) {
val queue = (new BasicIntQueue with Squaring)
queue.put(10)
queue.put(20)
println(queue.get()) // 100
println(queue.get()) // 400
}
}

super清單 6 中對 super 的使用說明了特征和混入之間的重要區(qū)別。因為您在創(chuàng)建原始的類后(確實)混入了它們,所以混入必須解決類層次結(jié)構(gòu)中的當前位置上的潛在不確定性。特征在創(chuàng)建類的時候已被線性化;編譯器解決了什么是 super 的問題,沒有不確定性。嚴格定義的復雜規(guī)則(這超出了本文的范圍)控制了線性化在 Scala 中的工作方式。特征還為 Scala 解決了鉆石問題。當 Scala 跟蹤方法的源和解析時,不可能出現(xiàn)不確定性,因為該語言定義了明確的規(guī)則來處理解析。

結(jié)束語

在本期文章中,我探討了混入(在 Groovy 中)和特征(在 Scala 中)之間的異同。混入和特征提供了許多相似的特性,但在實現(xiàn)細節(jié)方面有所不同,在某些重要方面,說明了不同的語言哲學。在 Groovy 中,混入是以注釋的形式存在的,并使用了 AST 轉(zhuǎn)換所提供的強大元編程功能。混入、類別類和 ExpandoMetaClass 在功能上有些重疊,它們有微?。ǖ匾┑牟町悺VT如 Ordered 之類的 Scala 中的特征形成了 Scala 中大部分內(nèi)置功能所依賴的核心語言特性。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • 一文搞懂Java頂層類之Object類的使用

    一文搞懂Java頂層類之Object類的使用

    java.lang.Object類是Java語言中的根類,即所有類的父類。它中描述的所有方法子類都可以使用。本文主要介紹了Object類中toString和equals方法的使用,感興趣的小伙伴可以了解一下
    2022-11-11
  • 如何在Maven項目中運行JUnit5測試用例實現(xiàn)

    如何在Maven項目中運行JUnit5測試用例實現(xiàn)

    這篇文章主要介紹了如何在Maven項目中運行JUnit5測試用例實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-04-04
  • java?stream實現(xiàn)分組BigDecimal求和以及自定義分組求和

    java?stream實現(xiàn)分組BigDecimal求和以及自定義分組求和

    這篇文章主要給大家介紹了關于java?stream實現(xiàn)分組BigDecimal求和以及自定義分組求和的相關資料,Stream是Java8的一大亮點,是對容器對象功能的增強,它專注于對容器對象進行各種非常便利、高效的聚合操作或者大批量數(shù)據(jù)操作,需要的朋友可以參考下
    2023-12-12
  • Java+MySql圖片數(shù)據(jù)保存與讀取的具體實例

    Java+MySql圖片數(shù)據(jù)保存與讀取的具體實例

    之前一直沒有做過涉及到圖片存儲的應用,最近要做的東東涉及到了這個點,就做了一個小的例子算是對圖片存儲的初試吧
    2013-06-06
  • Java多線程及分布式爬蟲架構(gòu)原理解析

    Java多線程及分布式爬蟲架構(gòu)原理解析

    這篇文章主要介紹了Java多線程及分布式爬蟲架構(gòu)原理解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10
  • Java框架Quartz中的Trigger簡析

    Java框架Quartz中的Trigger簡析

    這篇文章主要介紹了Java框架Quartz中的Trigger簡析,所有類型的trigger都有TriggerKey這個屬性,表示trigger的身份;除此之外,trigger還有很多其它的公共屬性,這些屬性,在構(gòu)建trigger的時候可以通過TriggerBuilder設置,需要的朋友可以參考下
    2023-11-11
  • Java靈活使用枚舉表示一組字符串的操作

    Java靈活使用枚舉表示一組字符串的操作

    這篇文章主要介紹了Java靈活使用枚舉表示一組字符串的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • 將本地jar包安裝進入maven倉庫(實現(xiàn)方法)

    將本地jar包安裝進入maven倉庫(實現(xiàn)方法)

    下面小編就為大家?guī)硪黄獙⒈镜豭ar包安裝進入maven倉庫(實現(xiàn)方法)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • Java實戰(zhàn)之圖書管理系統(tǒng)的實現(xiàn)

    Java實戰(zhàn)之圖書管理系統(tǒng)的實現(xiàn)

    這篇文章主要介紹了如何利用Java語言編寫一個圖書管理系統(tǒng),文中采用的技術有Springboot、SpringMVC、MyBatis、ThymeLeaf 等,需要的可以參考一下
    2022-03-03
  • Java基于socket實現(xiàn)的客戶端和服務端通信功能完整實例

    Java基于socket實現(xiàn)的客戶端和服務端通信功能完整實例

    這篇文章主要介紹了Java基于socket實現(xiàn)的客戶端和服務端通信功能,結(jié)合完整實例形式分析了Java使用socket建立客戶端與服務器端連接與通信功能,需要的朋友可以參考下
    2018-05-05

最新評論