繁体   English   中英

如何在Java 8编译时确保方法签名“实现”功能接口

[英]How to ensure at Java 8 compile time that a method signature “implements” a functional interface

在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::continuingHash LongHashes::randomHashLongHashes::randomHashLongHasher.hash(long x)具有相同的签名?

在过去,我也曾希望这样做,但不,你不能这样做。 但是你知道。 在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);
    ...
}

你要求没有这样的语法结构。 但是,您可以在显式将方法引用分配给接口时创建静态常量:

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将在运行时挂在内存中,您可以将此声明移动到单独的类(例如,嵌套),该类编译但从未加载。

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

class LongHashes {

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

    ... etc


    LongHashMap map = createHashMap(LongHashes.randomHash);

一种方法是返回一个LongHasher直接从LongHashes类:

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

但是这会为你的LongHashes类添加一些代码并将它与LongHasher接口联系起来,这可能并不理想(尽管这基本上就是你所要求的)。

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

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

在这里编写静态方法的函数:

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

我们并没有被迫在任何地方使用lambdas。

虽然我发现Tagir的答案是一个很好的黑客,但是当一个人创建一个新的哈希时,很容易忘记添加私有常量。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM