10

Java 8 中是否有implements方法关键字的类似物?

假设我有一个功能接口:

@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);
    }
}

将来我希望能够互换使用对这 3 种方法的任何引用作为参数。例如:

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

我怎样才能确保在编译时LongHashes::xorHashLongHashes::continuingHashLongHashes::randomHash具有相同的签名LongHasher.hash(long x)

4

6 回答 6

9

过去我也希望这样做,但不,你不能那样做。但你知道。Java 8 之前有 Java。请改为:

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);
    ...
}
于 2015-05-12T16:46:56.137 回答
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 在运行时会挂在内存中,您可以将此声明移动到单独的类(例如,嵌套),该类可以编译但从不加载。

于 2015-05-12T16:42:55.553 回答
3

您可以声明函数对象,而不是方法。

class LongHashes {

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

    ... etc


    LongHashMap map = createHashMap(LongHashes.randomHash);
于 2015-05-12T16:58:32.407 回答
1

LongHasher一种方法是直接从类中返回 a LongHashes

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

但这会向您的类添加一些代码LongHashes并将其与LongHasher接口联系起来,这可能是不可取的(尽管这本质上是您所要求的)。

于 2015-05-12T16:41:02.390 回答
1

或者只创建 3 个实现 LongHasher 的类。当你需要一个 LongHasher 时,获取或创建一个实例并传递它:

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

在此处将函数编写为静态方法:

  • 让人难以理解
  • 听起来像是在重新发明轮子;轮子是接口/类,通过在问题描述中的引号之间使用“接口”来暗示重新发明;-)

我们不必在任何地方都使用 lambda。

于 2015-05-29T07:27:54.577 回答
0

尽管我发现 Tagir 的回答是一个不错的 hack,但在创建新哈希器时很容易忘记添加私有常量。

像往常一样,在处理潜在的重构问题时,我认为测试就是答案:

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));
    }
}
于 2015-06-03T09:34:46.283 回答