2015-05-12 47 views
10

在Java 8中是否有任何模擬implements關鍵字的方法?如何在Java 8編譯時確保方法簽名「實現」功能接口

比方說,我有一個功能接口:

@FunctionalInterface 
interface LongHasher { 
    int hash(long x); 
} 

和3種靜態方法一庫「實行」此功能接口:

class LongHashes { 
    static int xorHash(long x) { 
     return (int)(x^(x >>> 32)); 
    } 
    static int continuingHash(long x) { 
     return (int)(x + (x >>> 32)); 
    } 
    static int randomHash(long x) { 
     return xorHash(x * 0x5DEECE66DL + 0xBL); 
    } 
} 

在未來,我希望能夠以交替方式使用這三種方法的任何參考作爲參數。例如:

static LongHashMap createHashMap(LongHasher hasher) { ... } 
... 
public static void main(String[] args) { 
    LongHashMap map = createHashMap(LongHashes::randomHash); 
    ... 
} 

我怎樣才能在編譯時保證LongHashes::xorHashLongHashes::continuingHashLongHashes::randomHash具有相同的簽名LongHasher.hash(long x)

+2

的(無關)旁白:你的哈希函數看起來像一個'LongToIntFunction'。 (我不確定是否應該引入這樣一個(新的)與現有結構「結構相同」的接口 - 但也許在給它一個*名稱*中有一些好處,以表明它將用於什麼。 ) – Marco13

回答

8

有沒有這樣的語法構造你所要求的。然而,你可以創建一個靜態常量,你明確的參考方法分配給你的接口:

class LongHashes { 
    private static final LongHasher XOR_HASH = LongHashes::xorHash; 
    private static final LongHasher CONTINUING_HASH = LongHashes::continuingHash; 
    private static final LongHasher RANDOM_HASH = LongHashes::randomHash; 

    static int xorHash(long x) { 
     return (int)(x^(x >>> 32)); 
    } 
    static int continuingHash(long x) { 
     return (int)(x + (x >>> 32)); 
    } 
    static int randomHash(long x) { 
     return xorHash(x * 0x5DEECE66DL + 0xBL); 
    } 
} 

這樣,你的編譯將打破,如果在不兼容的方式或者方法簽名或界面的變化。如果你想要,你可以聲明他們public並使用,而不是方法引用。

如果你關心這些靜態lambda會在運行時掛在內存中,你可以將這個聲明移動到單獨的類(例如,嵌套的),該類可以編譯但從不加載。

+0

這種方法在私有靜態方法中會更短:'LongHasher [] longHashes = {LongHashes :: xorHash,LongHashes :: randomHash,LongHashes :: proceedHash};'。 – Yahor

1

一種方法是直接從LongHashes類返回LongHasher

class LongHashes { 
    private static int xorHashImpl(long x) { 
    return (int)(x^(x >>> 32)); 
    } 
    static LongHasher xorHash() { 
    return LongHashes::xorHashImpl; 
    } 
} 

但增加了一些代碼,您LongHashes類和它關係到LongHasher接口,這可能是不希望(儘管這基本上你在問什麼)。

+1

它可以被簡化得更多,不可以:)你不需要'xorHashImpl'方法,只需要內聯lambda;你不需要'xorHash'作爲一個方法,只需要一個靜態字段。 – ZhongYu

9

我也希望這樣做,過去,但不是你不能這樣做。但你知道。有Java的Java的8之前做這個:

enum LongHashes implements LongHasher { 
    XOR { 
     @Override 
     public int hash(long x) { ... } 
    }, 
    CONTINUING { 
     @Override 
     public int hash(long x) { ... } 
    }, 
    RANDOM { 
     @Override 
     public int hash(long x) { ... } 
    } 
} 

然後:

public static void main(String[] args) { 
    LongHashMap map = createHashMap(LongHashes.RANDOM); 
    ... 
} 
+2

這對8歲以前的孩子很有好處。在Java 8中,它更簡單,直接lambda'XOR = x - > ...' – ZhongYu

+0

是否真的有可能在enum中使用這樣的語法? – Yahor

+3

@Yahor如果你的意思是,答案中的代碼是否可能,絕對是可能的。如果你的意思是在'enum'中是否可能'XOR = x->',否則;但你不需要枚舉,只需聲明靜態字段'LongHasher XOR = x - > {...}'它看起來像一個簡單的方法。 – ZhongYu

3

你可以聲明函數對象,而不是方法。

class LongHashes { 

    static final LongHasher xorHash = x -> { 
     return (int)(x^(x >>> 32)); 
    }; 

    ... etc 


    LongHashMap map = createHashMap(LongHashes.randomHash); 
1

或者只是創建3個實現LongHasher的類。當你需要一個LongHasher,獲取或創建一個實例,並把它傳遞:

LongHasher longHasher = ... // new RandomLongHasher(), factory, ....... 
LongHashMap map = createHashMap(longHasher); 

寫作功能爲靜態方法在這裏:

  • 使得它很難理解
  • 聽起來像重新發明輪子;輪子是接口/類,重新發現被問題描述中使用引號之間的「接口」暗示;-)

我們不是被迫在任何地方都使用lambdas。

0

儘管我發現塔吉爾的答案是一個很好的破解,但是很容易忘記在創建新的哈希器時添加私有常量。

像往常一樣,與潛在的重構問題時,我認爲測試是答案:

public class LongHashesTest { 

    @Test 
    public void xorHash() { 
     LongHasher xorHash = LongHashes::xorHash; 

     assertEquals(1768181579, xorHash.hash(34312465426524234l)); 
    } 

    @Test 
    public void continuingHash() { 
     LongHasher continuingHash = LongHashes::continuingHash; 

     assertEquals(1529080340, continuingHash.hash(74543524355l)); 
    } 

    @Test 
    public void randomHash() { 
     LongHasher randomHash = LongHashes::randomHash; 

     assertEquals(-1100764221, randomHash.hash(4343245345432154353l)); 
    } 
}