I have a abstract class A, class B is concrete class that 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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With