views:

94

answers:

6

hello to all

I have a small problem in my code

I have 2 classes

public class A {

     public A foo(int a) {return new A();}
}

public class B extends A{

     public B foo(int x){ return new B();}
}

now in my code I want to print only the method that was declared in class B

in this way

B b = new B();

Method[] m = b.getClass().getDeclaredMethods();

for (int i = 0; i < m.length; i++) {

System.out.print(m[i].getName());   
}

why the output is

foo

foo

why the GetDeclaredMethods finds also the foo in the A class? how can i fix it?

thanks

A: 

You can call m.getDeclaringClass() to see if it's the Method from Class A or Class B.

Jim Ferrans
in both cases the getDeclaringClass returns B
Dazel
+1  A: 

By default, getDeclaredMethods() returns all of the methods for the given class, as well as it's parent classes and interfaces. However, the Method object allows you to test which class a Method belongs to by calling getDeclaringClass() on that Method. So when you cycle through all the Method objects, you can add logic to only print a method if it belongs to the B class.

Method[] m = b.getClass().getDeclaredMethods();
for (int i = 0; i < m.length; i++) {
  if (m[i].getDeclaringClass().equals(B.class)) {
    System.out.print(m[i].getName());
  }
}

EDIT: The above code doesn't work as desired -- it returns B as the declaring class of all methods. The isSynthetic() method appears to work as desired, returning true for an overridden method (one that came from A), but false for one that came from B. So the following code might be what you're looking for.

Method[] m = b.getClass().getDeclaredMethods();
for (int i = 0; i < m.length; i++) {
  if (!m[i].isSynthetic()) {
    System.out.print(m[i]);
  }
}
Kaleb Brasee
sorry but this is not the correct solutionI still Get 2 foo in the output
Dazel
Lemme run it and see what the problem is...
Kaleb Brasee
I found the method isSynthetic()It return false for the original foo in class Band return true for the foo from class Abut because I not familiar with the isSynthetic() methodI'm not sure that this the correct use of it. Is this the right place to use this method?
Dazel
You're right -- isSynthetic() does work. I'm not exactly sure why though, from what I've read synthetic means dynamically generated at runtime, not by the compiler. Maybe the compiler dynamically adds `public A foo(int)` to class B, because of the superclass? Not sure... will look into this further.
Kaleb Brasee
getDeclaredMethods does NOT return the methods from parent classes or interfaces, or is the javadoc wrong?
Carlos Heuberger
Well, I was testing this code in Java 1.6 -- and it was returning 2 methods, `A foo(int)` and `B foo (int)`. It said both belong have `B` as the declaring class.
Kaleb Brasee
+1  A: 

Because B.foo and A.foo is different methods. If you want to override method A.foo, then method B.foo must return class A.

Orsol
Correct answer, so +1, but it is not very well expressed if you don't already understand the answer.
Yishai
A: 

This may work:

A a = new A();
B b = new B();

List<Method> aMethods = Arrays.asList(a.getClass().getMethods());
List<Method> bMethods = Arrays.asList(b.getClass().getMethods());

for ( Method m : bMethods )
{
  if( ! aMethods.contains(m) )
  {
  //Your action code here
  }
}
instanceofTom
+5  A: 

The reason you are having a problem is because of the covariant return types of your two methods. Because you have a covariant return type (the return type of B is B, not A, unlike the superclass), Java under the hood generates a separate method with the original return type to act as a bridge between the pre-1.5 bytecode specification the new Java 1.5 language behavior.

The method you should be using to check, though is the isBridge() method, as it expresses exactly what you intend to exclude. So the final code would look something like this:

Method[] methods = B.class.getDeclaredMethods();

for (Method method : methods) {

   if (!method.isBridge()) {
       System.out.println(method.getName());
   }   
}
Yishai
Its seems to be the solution to my problem, thank youBut what the difference between IsBridge() and isSynthetic()?
Dazel
@Dazel, basically isBridge identifies things which are done by the Java compiler to fit a Java language features introduced by Generics into bytecode limitations. isSynthetic tells you if the method is synthetically generated, which bridge methods are, but more things are as well, such as some elements of inner classes. So a bridge is always synthetic, but a synthetic isn't always a bridge. Thinking about it further, synthetic might be what you care about most - the method doesn't exist in the source code, you don't care why.
Yishai
Nice, I never realized this. Seems that some of the things they had to do to get Java working with the 1.5-and-up spec are... interesting.
Kaleb Brasee
A: 

When you says if( ! aMethods.contains(m) ) does contains compare by name? arguments type? return value type? because the only difference from the wanted method to the not is the covariance return type...

T_lord
another difference: one is a bridge method (also synthetic), but this is not checked by `equals`). `contains` use the `equals` method, and the documentation from `Method.equals` says: "... Returns true if the objects are the same. Two Methods are the same if they were declared by the same class and have the same name and formal parameter types and return type."
Carlos Heuberger