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

时间:2013-07-12 21:41:31

标签: 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 Class1 {

    @TestAnno
    public void test1() { }

    public void test2() { }

}

package pkg1;

import pkg3.TestAnno;

public class Class2 extends Class1 {

    @TestAnno
    public void test3() { }

    public void test4() { }

}

最后我在包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");
            }
        }

    }

}

运行这个例子我希望看到信息,两个方法都有@TestAnno存在 - test1和test3,但我只看到一个test3,而且...奇怪的是,方法test1和test2被列为原样在Class2类中声明。

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获取带注释的公共方法?

1 个答案:

答案 0 :(得分:0)

这个答案只是一个男人在凌晨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()

如您所见,使用包修饰符扩展类的公共类不会继承注释,但包含修饰符的类会继承注释。


为什么?
SomeDefaultClassSomePublicClass“都继承了”test()方法,但不是以同样的方式。

如果您查看javap SomeDefaultClass.class的结果,您会看到

class SomeDefaultClass extends SomeClass {
  SomeDefaultClass();
}

因此它的二进制文件中没有test()方法,因此它将使用SomeClass中有TestAnno注释的方法。

另一方面,如果您查看javap SomePublicClass的结果,您会看到

public class SomePublicClass extends SomeClass {
  public SomePublicClass();
  public void test();
}

这意味着test()方法的代码已在SomePublicClass中被覆盖,因此此方法已在SomePublicClass中再次声明,但 在以前没有注释 > 并且由于重写方法没有注释,因此您不会在代码中看到它们。 (为什么在编译器重写方法时不添加注释?老实说,我不知道:/)

为什么压倒一切?我怀疑,因为SomePublicClass 公开 test也是 公开 ,所以可以从所有包中访问,但由于SomeClass具有默认/包可见性,因此无法通过SomeClass从其包外部访问此方法。


为防止将test方法从一个类移动/复制到另一个类,您可以同时创建publicdefault/package个类。