Problem in the GetDeclaredMethods (java) - java

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

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());
}
}

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]);
}
}

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.

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

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
}
}

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...

Related

Why am I not able to assign a nested class to its parents?

Give the following code
interface C {
void g();
}
class A {
int x = 1;
C f() {
int y = 1;
class B extends A implements C {
public void g() {
A.this.x = y; // accessing x and y is OK.
}
}
B b = new B();
return b;
}
}
I tried to run the following line of commands:
A a = new A().f();
However, it throws an incompatible type error that C cannot be converted to A.
I do not understand why this is throwing an error as the text I was reading was executing the following commands:
A a = new A();
C b = a.f();
b.g();
And they mentioned that:
Calling the commands above will give us a reference to an object of type B now
What could be the cause of this behavior?
Edit: I ran the following codes on jshell.
Edit 2: Mistakes.
You need to consider compile time type information. Even though you can tell that B is an A and the C reference return from f() is an instance of B the compiler only knows that objects returned from f() implement C. It would be wrong to infer any concrete type. After all, you may return any concrete type from f() so long as it implements C. You could check manually by calling instanceof and or cast the instance A a = (A) new A().f(); but this is generally not a great idea. It will make your code break if you want to add additional C implementations.
The function f() of A returns an Object of class C. You cannot assign C to A. A would need to implement C for that.

Avoid code duplication over classes

I am writing some classes and all of them implement a certain method they inherit from an interface. This method is close to the same for all the classes beside one call to a certain other function.
For example:
public void doSomething(){
int a = 6;
int b = 7;
int c = anOtherMethod(a,b);
while(c < 50){
c++;
}
}
What if multiple classes have the function doSomething() but the implementation of the method anOtherMethod() is different?
How do I avoid code duplication in this situation? (This is not my actual code but a simplified version that helps me describe what I mean a bit better.)
This looks like a good example of the template method pattern.
Put doSomething in a base class.
Declare abstract protected anotherMethod in that base class as well, but don't provide an implementation.
Each subclass then provides the proper implementation for anotherMethod.
This is how you could implement the technique that Thilo talked about in the following demo:
Main class:
public class Main extends Method {
public static void main(String[] args) {
Method m = new Main();
m.doSomething();
}
#Override
public int anOtherMethod(int a, int b) {
return a + b;
}
}
Abstact class:
public abstract class Method {
public abstract int anOtherMethod(int a, int b);
public void doSomething() {
int a = 6;
int b = 7;
int c = anOtherMethod(a, b);
System.out.println("Output: "+c);
}
}
This way, all you have to do is override anOtherMethod() in each class that you want to use doSomething() with a different implementation of the method anOtherMethod().
Assuming every version of anOtherFunction takes two integers and returns an integer, I would just have the method accept a function as an argument, making it Higher Order.
A function that takes two arguments of the same type and returns an object of the same type is known as a BinaryOperator. You can add a argument of that type to the method to pass a function in:
// Give the method an operator argument
public void doSomething(BinaryOperator<Integer> otherMethod) {
int a = 6;
int b = 7;
// Then use it here basically like before
// "apply" is needed to call the passed function
int c = otherMethod.apply(a,b);
while(c < 50)
c++;
}
}
How you use it though will depend on your use case. As a simple example using a lambda, you can now call it like:
doSomething((a, b) -> a + b);
Which simply returns the sum of a and b.
For your particular case though, you may find that having doSomething as part of a Interface isn't necessary or optimal. What if instead, anOtherMethod is what's required to be supplied? Instead of expecting your classes to supply a doSomething, have them supply a BinaryOperator<Integer>. Then, when you need to get results from doSomething, get the operator from the class, then pass it to doSomething. Something like:
public callDoSomething(HasOperator obj) {
// There may be a better way than having a "HasOperator" interface
// This is just an example though
BinaryOperator<Integer> f = obj.getOperator();
doSomething(f);
}

Java virtual function calls

From my understanding all function-calls in Java are virtual, and numeral literals have the type int. But why does the Output in the example below differ?
public class A {
public int f(long d) {
return 2;
}
}
public class B extends A {
public int f(int d) {
return 1;
}
}
public class M {
public static void main(String[] args) {
B b = new B();
A ab = b;
System.out.println(b.f(1));
System.out.println(ab.f(1));
}
}
You dont override anything.
The first calling System.out.println(b.f(1)); returns 1, because it works with class B, even the method is named same, but parameters are different (long is not the same as int).
In case when parameters are same (int d), the result would be 1, because it overrides (#Override) the method from the class A.
Now, you know why the second calling System.out.println(ab.f(1)); returns 2. Look from what class it's called from.
Actually the subclass B has inherited the method f(with a long) and has added (overloaded) another method f(with a int).
When you write down a value such as 1 in such a way the compiler, even before assigning it to a typed reference does parse it as an int. More here: Java's L number (long) specification .
When you call the method f using the reference ab (which is A class) it (the reference) says I can only send you to a method f(with a long) and then implicitly cast the type int 1 into a long.
Let's try to change the type of the method in A class to f(short),
then System.out.println(ab.f(1)); will give you this error:
"The method f(short) in the type A is not applicable for the arguments (int)"

Mockito Verify on passed sub type only sees super type

I cannot easily verify 2 individual and unique call of a sub type class to a method which takes a supertype
I have a scenario that acts like this...
Both B and C extend abstract type A
With
public class X {
public String doSomething(A a){
return "";
}
}
Test
#Test
public void testExtensionVerify(){
X x = mock(X.class);
B b = new B();
C c = new C();
x.doSomething(b);
x.doSomething(c);
verify(x, times(1)).doSomething(any(B.class)); //fails.
}
verify times(1) fails... It sees 2 calls instead of 1 probably because B's reference in the method signature is the super type A.
The problem is that I cannot verify each call uniquely
I know that I can swtich to eq(b) and eq(c) instead of any() but I have no handle to them in my real case as they are created in the Object under test. Another option might be to do a ArgumentCaptor and test the instance but its annoying.
Any other solutions?
You can use isA:
verify(x, times(1)).doSomething(isA(B.class));
http://docs.mockito.googlecode.com/hg/1.9.5/org/mockito/Matchers.html
The any family methods don't do any type checks, those are only here to avoid casting in your code. If you want to perform type checks use the isA(Class) method. This might however change (type checks could be added) in a future major release.
public class XTest {
#Test
public void testExtensionVerify(){
X x = mock(X.class);
B b = new B();
C c = new C();
x.doSomething(b);
x.doSomething(c);
verify(x, times(1)).doSomething(isA(B.class));
verify(x, times(1)).doSomething(isA(C.class));
}
}

Why does sysout(upper class) invoke toString of lower class after assigning lower class to upper class?

I have two classes A and B while B is a subtype of A:
public class A {
private String stringVar;
public A() {
stringVar = "";
}
public String getStringVar() {
return stringVar;
}
public void setStringVar(String str) {
this.stringVar = str;
}
#Override
public String toString() {
return getStringVar();
}
}
Class B:
public class B extends A {
private int intVar;
public B() {
intVar = 0;
}
public int getIntVar() {
return intVar;
}
public void setIntVar(int intVar) {
this.intVar = intVar;
}
#Override
public String toString() {
return super.toString() + " " + getIntVar();
}
}
As you can see in the following main method I assign the b to a. Now "a" can't invoke b's methods which is clear, because I'm using an instance of type A now. But it behaves like a B when toString is invoked. Curious, I would have expected toString of a. Why is this so?
public class Main {
public static void main(String[] args) {
A a = new A();
B b = new B();
b.setIntVar(200);
b.setStringVar("foo");
a = b;
System.out.println(a);
}
}
Because a points to the implementation of B.
And is declared as A.
So behavior of B. And methods visible of A.
To use B methods do like this
((B) a).getIntVar();
Think of it like this
Object o = new FancyObject();
When compiling this only Objects methods will be accepted even though it's a FancyObjcet with lots of methods.
To use the methods of FancyObject on o do like this.
Object o = new FancyObject();
(FancyObject o).fancyMethod();
Quote "because I'm using an instance of type A now" you are still using an instance of type B. You can see it like you have upcasted b but it's the same instance.
Picture cross linked from another site with credits in the picture, if this is against the rules then somebody is free to edit this part of my answer.
This is nature of inheritance / polymorphism and overriding methods.
Overrided methods will be determined in runtime based on objects real type and not based on reference type.
Therefore a.toString() is actually b.toString() because it is determined in runtime.
http://download.oracle.com/javase/tutorial/java/IandI/override.html
The concept you need to understand is the difference between References and Objects.
a is a reference (a local variable in this case) that points first to an Object of type A and then to an Object of type B.
The compiler knows that it must be of type A (or a subtype thereof), so it can safely call all methods A defines, but they will be called on the actual Object, not on the original Type of a.
This is polymorphism: The object that a holds has static type A, but it is still an Object of dynamic type B. Dynamic dispatch therefore chooses the overridden toString() defined in B.
That's exactly how Java's runtime polymorphism works. All that matters is the actual type at runtime. What you have done is take a reference to an A and point it at an instance of B. You have changed the type of the thing that a points to.
Try
a = (A)b;
No, B Overrides the toString method of A, so if an object is an instance of B, when you call its toString method, you get whatever method that instance has. In general, if you have an object and call its methods, the method called is the one that is in the instance, not in the variable type. The only exception is static methods.
In C++, this is not the case. The method called is the one of the variable type, if one exists, unless you explicitly select the above described behavior by making a method virtual.
That is called runtime polymorphism in OOP.

Categories

Resources