Class.getDeclaredMethods() of reflection unwanted behavior

I have a class A which is a abstract class, class B is concrete and extends A.

Calling B.class.getDeclaredMethods() returns class A's method signatures in addition to class B's but JAVA documentation says some thing different on getDeclaredMethods()

"This includes public, protected, default (package) access, and private methods, but excludes inherited methods."

So from above docs i was expecting method foo() which is inherited from abstract parent class should not be returned from getDeclaredMethods() call, but i am getting method foo() which is inherited from abstract parent class is returned from getDeclaredMethods() call.

import java.lang.reflect.*;

public class B extends A {
    public static void main(String[] args) throws Exception {
        Method[] methods = B.class.getDeclaredMethods();
        for (int i = 0; i < methods.length; i++) {
            System.out.println(methods[i]);
        }
    }
}


abstract class A {
    public void foo() {
    }
}

Can some one explain me this behavior.

enter image description here

Jon Skeet
people
quotationmark

The oddity isn't in getDeclaredMethods() - it's in the class file for B, with a body that just calls super.foo().

I don't fully understand it, but it appears to be related to foo() being a public method declared in a package-private superclass.

Some test cases:

  • A package-private, foo public (as per question): method is generated in B
  • A package-private, foo package-private: method isn't generated in B
  • A public, foo public: method isn't generated in B
  • A public, foo package-private: method isn't generated in B

I suspect the idea is that a third class in a different package can't "see" A, but A.foo() is still public, so it should (?) be accessible through B. In order to make it accessible, B needs to "redeclare" it.

It's not clear to me that this is actually correct - the (?) above. JLS 6.6.1 states (emphasis mine):

A member (class, interface, field, or method) of a reference type, or a constructor of a class type, is accessible only if the type is accessible and the member or constructor is declared to permit access

But this code is allowed in a different package:

B b = new B();
b.foo();

people

See more on this question at Stackoverflow