Java 方法注释和默认访问级别上的奇怪行为

Java 方法注释和默认访问级别上的奇怪行为,java,reflection,annotations,Java,Reflection,Annotations,这是我的问题 我在包pkg3中有一个注释: package pkg3; import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface TestAnno { } 另外,我在pkg1包中有两个类,一个具有公共访问权限,另一个具有默认访问权限 package pkg1; import pkg3.TestAnno; class C

这是我的问题

我在包pkg3中有一个注释:

package pkg3;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TestAnno {

}
另外,我在pkg1包中有两个类,一个具有公共访问权限,另一个具有默认访问权限

package pkg1;

import pkg3.TestAnno;

class Class1 {

    @TestAnno
    public void test1() { }

    public void test2() { }

}

最后,我在pkg2包中有一个主类

package pkg2;

import java.lang.reflect.Method;
import pkg1.Class2;
import pkg3.TestAnno;

public class MainClass {

    public static void main(String[] args) {

        Class2 cls = new Class2();
        for(Method m: cls.getClass().getMethods()) {
            System.out.println(m);
            if (m.getAnnotation(TestAnno.class) != null) {
                System.out.println("  > hass anno");
            }
        }

    }

}
运行这个示例时,我希望看到这样的信息:两个方法都没有@testnno-present-test1和test3,但我只看到一个test3,而且。。。奇怪的是,test1和test2方法是在类2中声明的

public void pkg1.Class2.test3()
  > hass anno
public void pkg1.Class2.test4()
public void pkg1.Class2.test1()
public void pkg1.Class2.test2()
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
... rest methods from java.lang.Object
我知道,getMethods只返回给定glass中的公共方法(它都是超类),但是。。。这对我来说很奇怪

我使用它是为了将生成的类(具有默认访问权限)与实现类(它们是公共的,并且正在扩展生成的类)分开。 我是否必须在生成的类中使用公共访问(我希望它们不被世界其他地方看到),或者是否有任何方法可以从Class1中获取带注释的公共方法?

这个答案只是一个人在凌晨3点提出的“一个大的可能”,因此需要JLS对抗、更好的术语和更多的信息。我本打算将其作为评论发布,但不幸的是,它太长了:/


让我们来看看这些课程

class SomeClass {
    @TestAnno
    public void test(){}
}

class SomeDefaultClass extends SomeClass {
}

public class SomePublicClass extends SomeClass {
}
现在看看这段代码及其结果

Method m1 = SomePublicClass.class.getMethod("test");
Method m2 = SomeDefaultClass.class.getMethod("test");

System.out.println(m1 + "\t> " + m1.getAnnotation(TestAnno.class));
System.out.println(m2 + "\t\t> " + m2.getAnnotation(TestAnno.class));
输出

public void SomePublicClass.test()  > null
public void SomeClass.test()        > @TestAnno()
正如您所看到的,使用包修饰符扩展类的公共类不会继承注释,但使用包修饰符扩展类会继承注释


为什么会这样?
SomeDefaultClass
SomePublicClass
都是“继承的”
test()
方法,但方式不同

如果您查看
javapsomedefaultclass.class的结果,您将看到

class SomeDefaultClass extends SomeClass {
  SomeDefaultClass();
}
因此,它的二进制文件中没有
test()
方法,因此它将从
SomeClass
使用它,该类具有
TestAnno
注释

另一方面,如果查看
javapsomepublicclass
的结果,您将看到

public class SomePublicClass extends SomeClass {
  public SomePublicClass();
  public void test();
}
这意味着
test()
方法的代码已在
SomePublicClass
中被重写,因此此方法已在
SomePublicClass
中再次声明,但不幸的是,没有以前的注释,并且由于被重写的方法没有注释,您将无法在代码中看到它们。(为什么在编译器重写方法时不添加注释?老实说,我不知道:/)

为什么会发生超越?我怀疑由于
SomePublicClass
public并且
test
也是public它应该可以从所有包中访问,但是由于
SomeClass
具有默认/package可见性,这个方法不能通过
SomeClass
从其包外部访问


为了防止将
test
方法从一个类移动/复制到另一个类,您可以将两个类
都设置为public
default/package

这是官方行为,但这是一种奇怪的策略。
public class SomePublicClass extends SomeClass {
  public SomePublicClass();
  public void test();
}