Class.getDeclaredMethods() of reflection peculiar behavior

The reason you get this is because the superclass has package level access. If you change the access modifier of class A to public (you'll need to put it in its own file), the extra method in B.class.getDeclaredMethods() disappears.

(Also note that the abstract modified on class A is a red herring: the same thing occurs when class A is not abstract)

This is a workaround in the Java compiler for a bug in reflection: although foo is a public method, it was defined in package scoped class A. You could reflect on class B, find the method, try to invoke it using reflection, only to get an IllegalAccessException.

The compiler will generate a bridge method in class B so that you can correctly reflectively invoke method foo.


This is best demonstrated if you make the method foo in A a final method, which makes it impossible to fix this reflection bug (it's not possible to override the method)

Classes A and B are in package abc and class C is in package def. Class C tries to reflectively invoke method foo on class B which is public, but it fails because it was defined in non-public class A.

Exception in thread "main" java.lang.IllegalAccessException: Class def.C can not access a member of class abc.A with modifiers "public final"

package abc;

public class B extends A {
}

class A {
    public final void foo() {
    }

}
package def;

import java.lang.reflect.Method;

import abc.B;

public class C {
    public static void main(String[] args) throws Exception {
        Method m = B.class.getMethod("foo");
        m.invoke(new B());
    }
}

Just removing the final keyword from method foo resolves the problem, because the compiler then inserts the synthetic bridge method in class B.


It's explained in this bug report:

http://bugs.java.com/view_bug.do?bug_id=6342411

Description

The program below fails at runtime with this error:

Exception in thread "main" java.lang.IllegalAccessException: Class refl.ClientTest can not access a member of class refl.a.Base with
modifiers "public"
        at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
        at java.lang.reflect.Method.invoke(Method.java:578)
        at refl.ClientTest.main(ClientTest.java:9)
========== test/refl/a/Base.java ========== 
     1  package refl.a; 
     2   
     3  class Base { 
     4      public void f() { 
     5          System.out.println("Hello, world!"); 
     6      } 
     7  } 
========== test/refl/a/Pub.java ========== 
     1  package refl.a; 
     2   
     3  public class Pub extends Base {} 
========== test/refl/ClientTest.java ========== 
     1  package refl; 
     2  import refl.a.*; 
     3  import java.lang.reflect.*; 
     4   
     5  public class ClientTest { 
     6      public static void main(String[] args) throws Exception { 
     7          Pub p = new Pub(); 
     8          Method m = Pub.class.getMethod("f"); 
     9          m.invoke(p); 
    10      } 
    11  }

EVALUATION

The proposal is to add bridge methods in these very rare cases to fix a problem in reflection with no other forseen fix or workaround. Specifically, we would generate a bridge method when a public method is inherited from a nonpublic class into a public class.


For the reasons listed by the other answers, sometimes the compiler have to add some tricky code to your class file; this can be in the form of fields, constructors or methods. However, it always mark those fields as synthetic. That's an actual modifier it adds, and you can check if the method is synthetic with the method:

method.isSynthetic()

So whenever you get all methods, filter your list with this method to select only the ones you actually declared in the source ;)

Other examples of synthetic code are: default constructors that get automatically added, a reference to the outer class in a field if you have a non-static inner-class.