Dropping and overloading the reflection method in Java

Please note that all the code is a simplified example to convey only the basic ideas of my question. It should compile and run, although after a little editing.

I have several classes that implement a common interface.

public interface Inter{} public class Inter1 implements Inter{} public class Inter2 implements Inter{} 

In a separate class, I have a list of Inter types that I use to store and delete Inter1 and Inter2 types based on user input.

 java.util.ArrayList<Inter> inters = new java.util.ArrayList<Inter>(); 

I also have many overloaded methods that relate to how each implementation interacts with each other, along with the default implementation for 2 "Inter" s.

 void doSomething(Inter in1, Inter in2){ System.out.println("Inter/Inter"); } void doSomething(Inter1 in1, Inter1 in2){ System.out.println("Inter1/Inter11"); } void doSomething(Inter2 in1, Inter1 in2){ System.out.println("Inter2/Inter1"); } 

Methods are periodically called like this:

 for(int i = 0; i < inters.size() - 1; i++){ for(int o = i+1; o < inters.size(); o++){ Inter in1 = inters.get(i); Inter in2 = inters.get(o); doSomething(in1.getClass().cast(in1), in2.getClass().cast(in2)); System.out.println("Class 1: " + in1.getClass().getName()); System.out.println("Class 2: " + in2.getClass().getName()); } } 

Example output from this:

 Inter/Inter Class 1: Inter Class 2: Inter Inter/Inter Class 1: Inter Class 2: Inter1 Inter/Inter Class 1: Inter1 Class 2: Inter1 

Looking at the exit, it is clear that doSomething (Inter in1, Inter in2) is called even when other methods need to be called. Interestingly, the class names returned are correct.

Why does Java have static method overloads when class types are defined at runtime using reflection? Is there a way to get Java to do this? I know that I can use reflection both Class.getMethod () and method.invoke () to get the results I want, but it would be so neat to do this when casting.

I understand that questions about such concepts have been asked before, but so far all the answers have been informative, no one has satisfied me. Duplicate sending looked like it would work, but that would mean processing a lot of code, as I often use this type of thing.

+4
source share
2 answers

It seems to me that we are talking about what is happening:

 doSomething(in1.getClass().cast(in1), in2.getClass().cast(in2)); 

Based on your surprise that the type that is being deduced is always Inter , you seem a little confused about what is going on here. In particular, it seems you think that in1.getClass().cast(in1) and in2.getClass().cast(in2) should lead to a different overload due to the different type of runtime. However, this is wrong.

Method overload resolution occurs statically. This means that this is based on the declared types of the two method arguments. Since both in1 and in2 are declared as Inter , the chosen method is obviously void doSomething(Inter in1, Inter in2) .

The conclusion here is that in1 declared as Inter . This means that in1.getClass() essentially matches Inter.class for static analysis purposes - getClass just returns a Class<? extends Inter> Class<? extends Inter> . Therefore, the drives are useless, and you will always get the first overload.

+6
source

The Java Language Specification (JLS) in section 15.12 Invoking a Method Call explains in detail the process that a compiler must follow in order to select the correct method to invoke.

There you will notice that this is a compile-time task. JLS says in subsection 15.12.2:

This step uses the method name and types of argument expressions to find methods that are available and applicable. There may be more than one such method, in which case the most specific one is selected.

In your case, this means that since you are passing two objects of type Integer , the most specific method is the one that gets exactly that.

To check the nature of compilation time, you can do the following testing.

Declare a class like this and compile it.

 public class ChooseMethod { public void doSomething(Number n){ System.out.println("Number"); } } 

Declare a second class that calls the method of the first and compile it.

 public class MethodChooser { public static void main(String[] args) { ChooseMethod m = new ChooseMethod(); m.doSomething(10); } } 

If you call main, the output says Number .

Now add a second more specific method to the ChooseMethod class and recompile it (but do not recompile another class).

 public void doSomething(Integer i) { System.out.println("Integer"); } 

If you run main again, the output will be Number .

Basically, because it was decided at compile time. If you recompile the MethodChooser class (the one with the main one) and run the program again, the output will be Integer .

Thus, if you want to force one of the overloaded methods to be selected, the type of arguments must match the type of parameters at compile time, and not just at run time, as you seem to expect from this exercise.

+1
source

Source: https://habr.com/ru/post/1403793/


All Articles