什么是嵌套类类型参数的注解方法之间的区别?

huangapple go评论77阅读模式
英文:

What is the difference between the approachs of annotation on nested class type parameter?

问题

org.jetbrains.annotations.NotNull

public static void func(Foo.Bar.@NotNull Baz arg0) {

}


public static void func(@NotNull Foo.Bar.Baz arg0) {

}


public static void func(@NotNull Foo.Bar.@NotNull Baz arg0) {

}

对于嵌套类类型参数的注解方法有什么区别?

哪种方法是推荐的?

英文:
org.jetbrains.annotations.NotNull

public static void func(Foo.Bar.@NotNull Baz arg0) {

}


public static void func(@NotNull Foo.Bar.Baz arg0) {

}


public static void func(@NotNull Foo.Bar.@NotNull Baz arg0) {

}

What is the difference between the approachs of annotation on nested class type parameter?

Which one is recommanded?

答案1

得分: 2

这些只是在语法上有所不同。从语义上讲,它们都表示“此参数不应为null”,实际上,这三种方式都会编译为对参数的相同空值检查。

之所以这三种方式都有效,是因为 NotNull 具有 ElementType.TYPE_USE 的元素类型,所以你可以使用 NotNull 注释任何“类型使用”。在 Foo.Bar 中的 Bar 是类型 Bar 的使用,因此你可以通过 Foo.@NotNull Bar 进行注释。

这引出了一个问题,为什么 NotNull 首先具有 ElementType.TYPE_USE。显然不是为了让你有三种表达完全相同的方式。更可能的原因是允许你这样做:

List<@NotNull String> listWithNotNullElements;

无论如何,这三种方式都会编译为相同的字节码,因为在这三种情况下,NotNull 注释的是 参数

以下这三种情况:

package io.github.sweeper777;
import org.jetbrains.annotations.NotNull;
public class Main {
    public static void main(String[] args) {
    }
    public void f( Foo.@NotNull Bar x) {
    }
}
class Foo {
    static class Bar {
    }
}
package io.github.sweeper777;
import org.jetbrains.annotations.NotNull;
public class Main {
    public static void main(String[] args) {
    }
    public void f(@NotNull Foo.@NotNull Bar x) {
    }
}
class Foo {
    static class Bar {
    }
}
package io.github.sweeper777;
import org.jetbrains.annotations.NotNull;
public class Main {
    public static void main(String[] args) {
    }
    public void f(@NotNull Foo.Bar x) {
    }
}
class Foo {
    static class Bar {
    }
}

编译为:

Compiled from "Main.java"
public class io.github.sweeper777.Main {
  public io.github.sweeper777.Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: return

  public void f(io.github.sweeper777.Foo$Bar);
    Code:
       0: aload_1
       1: ifnonnull     8
       4: iconst_0
       5: invokestatic  #36                 // Method $$$reportNull$$$0:(I)V
       8: return

  private static void $$$reportNull$$$0(int);
    Code:
       0: ldc           #38                 // String Argument for @NotNull parameter '%s' of %s.%s must not be null
       2: iconst_3
       3: anewarray     #2                  // class java/lang/Object
       6: dup
       7: iconst_0
       8: ldc           #39                 // String x
      10: aastore
      11: dup
      12: iconst_1
      13: ldc           #40                 // String io/github/sweeper777/Main
      15: aastore
      16: dup
      17: iconst_2
      18: ldc           #41                 // String f
      20: aastore
      21: invokestatic  #47                 // Method java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
      24: new           #49                 // class java/lang/IllegalArgumentException
      27: dup_x1
      28: swap
      29: invokespecial #52                 // Method java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V
      32: athrow
}
英文:

These are only syntactically different. Semantically, they all mean "this parameter should not be null", and practically, all three compiles to the same null check on the parameter.

The reason why all three works is because NotNull has the ElementType of TYPE_USE, so you can annotate any "type use" with NotNull. Well, the Bar in Foo.Bar is a use of the type Bar, so you can annotate that by doing Foo.@NotNull Bar.

This raises the question of why does NotNull have ElementType.TYPE_USE in the first place. It certainly is not to allow you to have 3 ways of saying the exact same thing. A more likely reason is to allow you to do this:

List&lt;@NotNull String&gt; listWithNotNullElements;

Anyway, all three of these compile to the same byte code, as in all 3 cases, NotNull is annotating the parameter.

All three of the following:

package io.github.sweeper777;
import org.jetbrains.annotations.NotNull;
public class Main {
    public static void main(String[] args) {
    }
    public void f( Foo.@NotNull Bar x) {
    }
}
class Foo {
    static class Bar {
    }
}
package io.github.sweeper777;
import org.jetbrains.annotations.NotNull;
public class Main {
    public static void main(String[] args) {
    }
    public void f(@NotNull Foo.@NotNull Bar x) {
    }
}
class Foo {
    static class Bar {
    }
}
package io.github.sweeper777;
import org.jetbrains.annotations.NotNull;
public class Main {
    public static void main(String[] args) {
    }
    public void f(@NotNull Foo.Bar x) {
    }
}
class Foo {
    static class Bar {
    }
}

Compiles to:

Compiled from &quot;Main.java&quot;
public class io.github.sweeper777.Main {
  public io.github.sweeper777.Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object.&quot;&lt;init&gt;&quot;:()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: return

  public void f(io.github.sweeper777.Foo$Bar);
    Code:
       0: aload_1
       1: ifnonnull     8
       4: iconst_0
       5: invokestatic  #36                 // Method $$$reportNull$$$0:(I)V
       8: return

  private static void $$$reportNull$$$0(int);
    Code:
       0: ldc           #38                 // String Argument for @NotNull parameter \&#39;%s\&#39; of %s.%s must not be null
       2: iconst_3
       3: anewarray     #2                  // class java/lang/Object
       6: dup
       7: iconst_0
       8: ldc           #39                 // String x
      10: aastore
      11: dup
      12: iconst_1
      13: ldc           #40                 // String io/github/sweeper777/Main
      15: aastore
      16: dup
      17: iconst_2
      18: ldc           #41                 // String f
      20: aastore
      21: invokestatic  #47                 // Method java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
      24: new           #49                 // class java/lang/IllegalArgumentException
      27: dup_x1
      28: swap
      29: invokespecial #52                 // Method java/lang/IllegalArgumentException.&quot;&lt;init&gt;&quot;:(Ljava/lang/String;)V
      32: athrow
}

huangapple
  • 本文由 发表于 2020年10月23日 14:46:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/64495164.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定