栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

注释Lambda表达式的功能接口

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

注释Lambda表达式的功能接口

在深入研究Java SE 8最终规范之后,我可以回答我的问题。

(1)回答我的第一个问题

有没有什么方法可以像注释相应的匿名类一样注释lambda表达式,因此可以在上面的示例中获得预期的“ Hello World”输出?

没有。

注释

Class Instance Creation expression(§15.9)
匿名类型的时,注释将存储在类文件中,用于扩展接口或匿名类型的扩展类。

对于以下匿名接口注释

Consumer<String> c = new @MyTypeAnnotation("Hello ") Consumer<String>() {    @Override    public void accept(String str) {        System.out.println(str);    }};

然后可以在 运行时 通过调用

Class#getAnnotatedInterfaces()
以下方式访问类型注释:

MyTypeAnnotation a = c.getClass().getAnnotatedInterfaces()[0].getAnnotation(MyTypeAnnotation.class);

如果使用这样的空主体创建一个匿名类:

class MyClass implements Consumer<String>{    @Override    public void accept(String str) {        System.out.println(str);    }}Consumer<String> c = new @MyTypeAnnotation("Hello ") MyClass(){};

类型注释也可以在 运行时 通过调用来访问

Class#getAnnotatedSuperclass()

MyTypeAnnotation a = c.getClass().getAnnotatedSuperclass().getAnnotation(MyTypeAnnotation.class);

这种类型的注释是 没有 可能的lambda表达式。

附带说明一下,这种注释对于普通的类实例创建表达式也是不可能的:

Consumer<String> c = new @MyTypeAnnotation("Hello ") MyClass();

在这种情况下,类型注释将存储在发生表达式的方法的method_info结构中,而不是类型本身(或其任何超类型的注释)。

这种差异很重要,因为Java反射API在运行时将 无法
访问存储在method_info中的注释。使用ASM查看生成的字节码时,区别如下:

在创建匿名接口实例时输入Annotation:

@Java8Example$MyTypeAnnotation(value="Hello ") : CLASS_EXTENDS 0, null// access flags 0x0INNERCLASS Java8Example$1

在普通的类实例创建时输入Annotation:

NEW Java8Example$MyClass@Java8Example$MyTypeAnnotation(value="Hello ") : NEW, null

在第一种情况下,注释与 内部类 相关联,在第二种情况下,注释与方法字节代码内的 实例创建 表达式相关联。

(2)回应@assylias的评论

您也可以尝试(@MyTypeAnnotation(“ H​​ello”)String s)->
System.out.println(s),尽管我尚未设法访问注释值…

是的,根据Java
8规范,这实际上是可能的。但是,目前尚无法通过Java反射API接收lambda表达式的形式参数的类型注释,这很可能与以下JDK错误有关:类型注释清除。此外,Eclipse编译器尚未在类文件中存储相关的Runtime
[In] VisibleTypeAnnotations属性-
在此处找到了相应的错误:Lambda参数名称和注释未将其添加到类文件中。

(3)回答我的第二个问题

在示例中,我确实强制转换了lambda表达式并注释了强制转换的类型:在运行时是否有任何方法可以接收此批注实例,或者这样的批注始终隐式地限于RetentionPolicy.SOURCE?

注释强制转换表达式的类型时,此信息也将存储在类文件的method_info结构中。对于方法代码(例如)中的类型注释的其他可能位置也是如此

if(cinstanceof @MyTypeAnnotationConsumer)
。当前没有公共Java反射API可以访问这些代码注释。但是由于它们存储在类文件中,因此至少有可能在运行时访问它们-
例如,通过使用外部库(如ASM)读取类的字节码。

实际上,我设法使我的“ Hello World”示例与强制转换表达式类似

testTypeAnnotation(list,(@MyTypeAnnotation("Hello ") Consumer<String>) (p -> System.out.println(p)));

通过使用ASM解析调用方法的字节码。但是代码非常hacky,效率低下,可能永远都不要在生产代码中做类似的事情。无论如何,仅出于完整性考虑,下面是完整的“
Hello World”示例:

import java.lang.annotation.Annotation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import java.lang.reflect.AnnotatedType;import java.lang.reflect.Method;import java.net.URL;import java.util.Arrays;import java.util.List;import java.util.function.Consumer;import org.objectweb.asm.AnnotationVisitor;import org.objectweb.asm.ClassReader;import org.objectweb.asm.ClassVisitor;import org.objectweb.asm.Label;import org.objectweb.asm.MethodVisitor;import org.objectweb.asm.Oppres;import org.objectweb.asm.TypePath;import org.objectweb.asm.TypeReference;public class Java8Example {    @Retention(RetentionPolicy.RUNTIME)    @Target(ElementType.TYPE_USE)    public @interface MyTypeAnnotation {        public String value();    }    public static void main(String[] args) {        List<String> list = Arrays.asList("World!", "Type Annotations!");        testTypeAnnotation(list, new @MyTypeAnnotation("Hello ") Consumer<String>() { @Override public void accept(String str) {     System.out.println(str); }        });        list = Arrays.asList("Type-Cast Annotations!");        testTypeAnnotation(list,(@MyTypeAnnotation("Hello ") Consumer<String>) (p -> System.out.println(p)));    }    public static void testTypeAnnotation(List<String> list, Consumer<String> consumer){        MyTypeAnnotation annotation = null;        for (AnnotatedType t :  consumer.getClass().getAnnotatedInterfaces()) { annotation = t.getAnnotation(MyTypeAnnotation.class); if (annotation != null) {     break; }        }        if (annotation == null) { // search for annotated parameter instead loop: for (Method method : consumer.getClass().getMethods()) {     for (AnnotatedType t : method.getAnnotatedParameterTypes()) {         annotation = t.getAnnotation(MyTypeAnnotation.class);         if (annotation != null) {  break loop;         }     } }        }        if (annotation == null) { annotation = findCastAnnotation();        }        for (String str : list) { if (annotation != null) {     System.out.print(annotation.value()); } consumer.accept(str);        }    }    private static MyTypeAnnotation findCastAnnotation() {        // foundException gets thrown, when the cast annotation is found or the search ends.        // The found annotation will then be stored at foundAnnotation[0]        final RuntimeException foundException = new RuntimeException();        MyTypeAnnotation[] foundAnnotation = new MyTypeAnnotation[1];        try { // (1) find the calling method StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); StackTraceElement previous = null; for (int i = 0; i < stackTraceElements.length; i++) {     if (stackTraceElements[i].getMethodName().equals("testTypeAnnotation")) {         previous = stackTraceElements[i+1];     } } if (previous == null) {     // shouldn't happen     return null; } final String callingClassName = previous.getClassName(); final String callingMethodName = previous.getMethodName(); final int callingLineNumber = previous.getLineNumber(); // (2) read and visit the calling class ClassReader cr = new ClassReader(callingClassName); cr.accept(new ClassVisitor(Oppres.ASM5) {     @Override     public MethodVisitor visitMethod(int access, String name,String desc, String signature, String[] exceptions) {         if (name.equals(callingMethodName)) {  // (3) visit the calling method  return new MethodVisitor(Oppres.ASM5) {      int lineNumber;      String type;      public void visitLineNumber(int line, Label start) {          this.lineNumber = line;      };      public void visitTypeInsn(int oppre, String type) {          if (oppre == Oppres.CHECKCAST) {   this.type = type;          } else{   this.type = null;          }      };      public AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {          if (lineNumber == callingLineNumber) {   // (4) visit the annotation, if this is the calling line number AND the annotation is    // of type MyTypeAnnotation AND it was a cast expression to "java.util.function.Consumer"   if (desc.endsWith("Java8Example$MyTypeAnnotation;") && this.type != null && this.type.equals("java/util/function/Consumer")) {       TypeReference reference = new TypeReference(typeRef);       if (reference.getSort() == TypeReference.CAST) {return new AnnotationVisitor(Oppres.ASM5) {    public void visit(String name, final Object value) {        if (name.equals("value")) { // Heureka! - we found the Cast Annotation foundAnnotation[0] = new MyTypeAnnotation() {     @Override     public Class<? extends Annotation> annotationType() {         return MyTypeAnnotation.class;     }     @Override     public String value() {         return value.toString();     } }; // stop search (Annotation found) throw foundException;        }    };};       }   }          } else if (lineNumber > callingLineNumber) {   // stop search (Annotation not found)   throw foundException;          }          return null;      };  };         }         return null;     } }, 0);        } catch (Exception e) { if (foundException == e) {     return foundAnnotation[0]; } else{     e.printStackTrace(); }        }        return null;    }}


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/483280.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号