3

这是我的问题...

我在包 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被列出,因为它们被声明在类 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 只返回给定玻璃的公共方法(而且都是超类)但是......这对我来说很奇怪。

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

4

1 回答 1

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.

于 2013-07-13T01:07:32.903 回答