Accessing grandparent's overridden methods.

K

Kira Yamato

class A
{
public int showMe() { System.out.println("A"); }
}

class B extends A
{
public int showMe() { System.out.println("B"); }
}

class C extends A
{
public int showMe() { System.out.println("C"); }

public void test()
{
showMe(); // prints C
super.showMe(); // prints B

// Question: how can I access class A's showMe()?
// I'm suspecting this cannot be done without modifying codes
outside of class C.
}
}

Thanks.
 
M

Mark Rafn

[ B extends A, C extends B, each implements/overrides showMe() ]

Kira Yamato said:
Question: how can I [in class C] access class A's showMe()?
I'm suspecting this cannot be done without modifying codes
outside of class C.

1) if you need to do this, you've probably got a broken object model. You
shouldn't know or care about it's implementation beyond what method signatures
are available to you.

2) If you really need it, you could use reflection.
this.getClass().getSuperclass().getSuperclass().getMethod("showMe", null)
will get you the Method you want to call.
 
L

Lasse Reichstein Nielsen

Kira Yamato said:
class A
{
public int showMe() { System.out.println("A"); }
}

class B extends A
{
public int showMe() { System.out.println("B"); }
}

class C extends A

You mean "extends B" for the question to make sense.
{
public int showMe() { System.out.println("C"); }

public void test()
{
showMe(); // prints C
super.showMe(); // prints B

// Question: how can I access class A's showMe()?

You can't.
Perhaps using reflection, but that's sidestepping a restriction
that is there for a reason.

A more relevant question is: Why do you want to? Should you instead
change your model or class hierarchy so that it matches what you want
to do with it?
// I'm suspecting this cannot be done without modifying codes
outside of class C.

Correct.

/L
 
P

Patricia Shanahan

Mark said:
[ B extends A, C extends B, each implements/overrides showMe() ]

Kira Yamato said:
Question: how can I [in class C] access class A's showMe()?
I'm suspecting this cannot be done without modifying codes
outside of class C.

1) if you need to do this, you've probably got a broken object model. You
shouldn't know or care about it's implementation beyond what method signatures
are available to you.

Strongly agree. Either C should not be calling A's method, or B's
version does not do the same job as A's method, and should have a
different name.

2) If you really need it, you could use reflection.
this.getClass().getSuperclass().getSuperclass().getMethod("showMe", null)
will get you the Method you want to call.

This does not seem to work. However, to be fair, I was not really
expecting it to work so I may have missed something. Please review. I get:

Direct showMe call
C
Super call
B
Refection call
C

when I run the following. Note that I would only throw "Exception" in a
test program, where I want any problem in the reflection, no matter what
it is, to flow to the top and crash the program.

public class ReflectionTest {

public static void main(String[] args)
throws Exception {
new C().test();
}

static class A {
public void showMe() {
System.out.println("A");
}
}

static class B extends A {
public void showMe() {
System.out.println("B");
}
}

static class C extends B {
public void showMe() {
System.out.println("C");
}

public void test() throws Exception {
System.out.println("Direct showMe call");
showMe(); // prints C
System.out.println("Super call");
super.showMe(); // prints B
System.out.println("Refection call");
Method grandparentMethod =
getClass().getSuperclass().getSuperclass()
.getMethod("showMe", (Class[]) null);
grandparentMethod.invoke(this, new Object[0]);
}
}

}
 
K

Kira Yamato

You mean "extends B" for the question to make sense.


You can't.
Perhaps using reflection, but that's sidestepping a restriction
that is there for a reason.

A more relevant question is: Why do you want to?

I don't. It's just an academic question.
Should you instead
change your model or class hierarchy so that it matches what you want
to do with it?

And you're right. In a proper design, I should've given these methods
different signature so that I can differentiate them in class C.

Thanks.
 
K

Kira Yamato

[ B extends A, C extends B, each implements/overrides showMe() ]

Kira Yamato said:
Question: how can I [in class C] access class A's showMe()?
I'm suspecting this cannot be done without modifying codes
outside of class C.

1) if you need to do this, you've probably got a broken object model. You
shouldn't know or care about it's implementation beyond what method signatures
are available to you.

Good point. I'm just trying to readjust from the C++ mindset here.
2) If you really need it, you could use reflection.
this.getClass().getSuperclass().getSuperclass().getMethod("showMe", null)
will get you the Method you want to call.

I think the dynamic method lookup mechanism would still cause the
program to give me C's version of the method again.

Anyway, it was just an academic question. As you pointed out, a proper
object design should not require this need.

Thanks.
 
M

Mark Rafn

Patricia Shanahan said:
This does not seem to work. However, to be fair, I was not really
expecting it to work so I may have missed something. Please review. I get:

You're right - this won't work. You'll ALWAYS invoke the appropriate showMe()
for the object passed as the first argument of invoke(), regardless of which
ancestor class you got the Method from.

Good :)
 
P

proudbug

You're right - this won't work.  You'll ALWAYS invoke the appropriate showMe()
for the object passed as the first argument of invoke(), regardless of which
ancestor class you got the Method from.

Good :)

To make it work, you just need to use "new A()" as the first argument
of invoke(), instead of "this".
 
P

Patricia Shanahan

proudbug said:
To make it work, you just need to use "new A()" as the first argument
of invoke(), instead of "this".

It depends what you mean by "work". In this, extremely simple, situation
all instances of A do exactly the same thing on showMe() call.

In more realistic situations, a new A() would not necessarily produce
the behavior of the A showMe for the the C instance doing the call.

Patricia
 
J

Joshua Cranmer

Kira said:
// Question: how can I access class A's showMe()?

The short answer, as others have answered, you can't.
The longer, more esoteric answer:
The Java bytecode has two [*] means of calling non-static methods:
invokevirtual and invokespecial (or invokenonvirtual). The difference
between the two is in how the VM selects the method to invoke: the
virtual one starts its way from the "runtime class" and works up to find
the method, the latter from the "compile-time class" (not the most
precise terms).

When a method is called in Java, the compiler selects the virtual flavor
except in one of two circumstances:
1. The method is private.
2. The method is called using super.

In the latter case, only one super can appear (so super.super is not
possible). This means in practice that the only control one has in the
second case is to choose nonvirtual methods based on the immediate
superclass and not other ancestors, a limitation not present in the
bytecode.

In short: it's possible if you're directly writing the bytecode.

[*] There are five invoke opcodes: invokespecial, invokevirtual,
invokeinterface, invokestatic, and invokedynamic. The latter are
excluded because invokeinterface is essentially an invokevirtual,
invokestatic uses static methods which do not inherit, and invokedynamic
is an opcode for languages over than Java.
 
K

Kira Yamato

Kira said:
// Question: how can I access class A's showMe()?

The short answer, as others have answered, you can't.
The longer, more esoteric answer:
The Java bytecode has two [*] means of calling non-static methods:
invokevirtual and invokespecial (or invokenonvirtual). The difference
between the two is in how the VM selects the method to invoke: the
virtual one starts its way from the "runtime class" and works up to
find the method, the latter from the "compile-time class" (not the most
precise terms).

When a method is called in Java, the compiler selects the virtual
flavor except in one of two circumstances:
1. The method is private.
2. The method is called using super.

In the latter case, only one super can appear (so super.super is not
possible). This means in practice that the only control one has in the
second case is to choose nonvirtual methods based on the immediate
superclass and not other ancestors, a limitation not present in the
bytecode.

In short: it's possible if you're directly writing the bytecode.

[*] There are five invoke opcodes: invokespecial, invokevirtual,
invokeinterface, invokestatic, and invokedynamic. The latter are
excluded because invokeinterface is essentially an invokevirtual,
invokestatic uses static methods which do not inherit, and
invokedynamic is an opcode for languages over than Java.

Thanks for the information on the inner workings of java. I have
subsequently found the java 3.0 spec. and am currently studying it.
 
P

proudbug

It depends what you mean by "work". In this, extremely simple, situation
all instances of A do exactly the same thing on showMe() call.

In more realistic situations, a new A() would not necessarily produce
the behavior of the A showMe for the the C instance doing the call.

Patricia- Hide quoted text -
I see your point. Thanks.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,981
Messages
2,570,187
Members
46,728
Latest member
FernMcmull

Latest Threads

Top