1

Given a situation like the following:

interface A<T>{
    default void foo(T t){
        System.err.println(new Exception().getStackTrace()[0] + " " + t);
    }
}

interface B<T extends SomeConcreteType> extends A<T>{
    @Override
    default void foo(T t){
        System.err.println(new Exception().getStackTrace()[0] + " " + t);
    }
}

I'm trying to use reflection to go from a B's foo method to A's foo method. Given that the post erasure parameter types of the two methods are different, how can I do this?

user1837841
  • 316
  • 1
  • 8
  • I'm thinking that this probably isn't possible in general. – user1837841 Dec 08 '19 at 17:37
  • tried `class.getMethod("foo").getDeclaringClass();`? From [here](https://stackoverflow.com/questions/2315445/how-to-quickly-determine-if-a-method-is-overridden-in-java). – Curiosa Globunznik Dec 08 '19 at 18:02
  • I am not sure that "the post erasure parameter types of the two methods are different". Actually (and skipping over "post erasure", which doesn't really make sense), the methods have the same parameter types. – Daniele Dec 08 '19 at 18:18
  • 2
    Not sure what you're trying to do and why you think you need reflection for it. What's wrong with `super.foo(t)`? – Costi Ciudatu Dec 08 '19 at 19:16
  • When you try to access a method via Reflection, it doesn’t matter from where you are doing it, the form will always be the same, i.e. `A.class.getDeclaredMethod("foo", Object.class)`, whether you are inside `B.foo` or `Hello.main`. So the erased parameter type of `B.foo` is entirely irrelevant. – Holger Dec 09 '19 at 10:51
  • @Daniele “post erasure” means “after applying type erasure”, which is relevant when you access a method via Reflection, as you have to specify the erased types. – Holger Dec 09 '19 at 10:52

1 Answers1

1

Java compiler in such case will generate 2 methods, so you can use both of them, one of them will have the same signature as in A.class: foo(Object) as it is required for overriding to work, and second one will have the basic generic type foo(SomeConcreteType), and the first method is just calling the second one, so basically after compilation your A and B class looks like this:

interface A<T>{
    default void foo(Object t){
        System.err.println(new Exception().getStackTrace()[0] + " " + t);
    }
}

interface B<T extends SomeConcreteType> extends A<T>{
    @Override
    default void foo(Object t){ 
        this.foo((SomeConcreteType) t);
    }

    default void foo(SomeConcreteType t){
        System.err.println(new Exception().getStackTrace()[0] + " " + t);
    }
}

(while skipping the generic metadata)

So you can just use A/B.class.getDecalredMethod("foo", Object.class) or B.class.getDecalredMethod("foo", SomeConcreteType.class)

GotoFinal
  • 3,585
  • 2
  • 18
  • 33