在某些接口上限制lambdas



假设我有几个带有一个抽象方法的接口。拥有这些接口,我可以用它声明lambdas:

interface A {
    int c();
}
interface B {
    int c();
}
public class Main {
    public static void main(String... args) {
        A a = () -> 42;
        B b = () -> 42;
    }
}

简短的问题:使用lambdas的接口A是否有一些技巧或黑客限制,并在尝试这样做时构建失败?欢迎任何提示,无论是否肮脏,都表示"肮脏",是指汇编/字节码级别的黑客 - 不会影响来源,最好是公共合同)。

长篇小说:对于某些接口实施者,我认为将equals/hashCode定义为合同的一部分。另外,我会在构建时间自动生成equals/hashCode

在这种情况下,Lambdas是麻烦制造者。对于接口A的普通和匿名实施者,我可以在构建时找到一个.class文件并仪器的字节码。对于Lambdas,有在运行时生产的VM匿名类。在构建时间上影响这样的类似乎是不可能的,所以我至少需要禁止针对特定界面的这种情况。

请查看我的解决方案:

package com.example.demo;
public class LambdaDemo {
    public static void main(String[] args) {
        //doesn't compile
        //LambdaRestrictedInterface x = () -> {};
        LambdaRestrictedInterface y = new Test();
        y.print();
    }
    private static class Test implements LambdaRestrictedInterface {
        @Override
        public void print() {
            System.out.println("print");
        }
    }
    public interface MyInterface {
        void print();
    }
    public interface LambdaRestrictedInterface extends MyInterface {
        @Override
        default void print() {
            //hack prevents lambda instantiating
        }
    }
}

https://dumpz.org/2708733/

想法是用默认的impl

覆盖父接口

从发起人编辑:在考虑之后,我决定接受此答案(因为它适合我的需求最佳,并且实现非常便宜)。实际上,已经意识到最小仪器足以防止将接口用作lambda-type,只是将默认实现添加到其抽象方法中。

从一点点播放中,看起来invokedynamic调用的desc字段包含正在实现的接口。例如,当我创建一个简单的() -> {}运行,然后通过ASM字节码轮廓插件将其传递时," ASM-IFIEF"调用看起来像:

mv.visitInvokeDynamicInsn("run", "()Ljava/lang/Runnable;", new Handle...

因此,如果您能够在呼叫网站上执行构建时间黑客(与以某种方式将注释本身标记为不可用的lambda-able,我认为您不能这样做),那么您应该是能够首先编译一组不允许的接口,然后检查invokedynamic的desc。

相关内容

  • 没有找到相关文章

最新更新