📜 ⬆️ ⬇️

the Da Vinci Machine Project in Java 7 and fighting bikes

Good afternoon, dear habrazhiteli!

Quite recently, many expected Java 7 . Unfortunately, many were disappointed by the composition of the innovations, as it did not include various very expected goodies like Project Lambda . However, there are still a lot of innovations and today I would like to dwell on one of the most important - the Da Vinci Machine Project , which allows you to use dynamic languages ​​on the JVM more effectively. If it says more precisely, then we will consider one of the parts of the Da Vinci Machine Project - the method handle . I didn’t have time to fully understand the concepts of this part of the language, but most people don’t understand why it is necessary. It, of course, concerns the overloading of methods and the passing of parameters through the interface.

It is known that in Java the decision on which of the overloaded methods to call is made at the compilation stage (unlike, say, C #, where it is done at runtime). Suppose we have the following code:
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
  1. class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
  2. class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
  3. class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
  4. class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
  5. class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
  6. class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
  7. class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
  8. class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
  9. class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
  10. class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
  11. class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
  12. class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
  13. class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
  14. class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
  15. class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
  16. class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
  17. class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .

According to Java rules, the public void call(A a) method will be called, and the “A” is displayed accordingly, which may seem strange because the actual type of object is B In order to call the method we need, we need to rewrite the code for calling the method like this:
  1. if (b instanceof B) {
  2. test.call ((B) b);
  3. }
* This source code was highlighted with Source Code Highlighter .


This approach has the right to life, but if you have dozens of such classes, then the code becomes banal and ugly, there is duplication and in general.
')
In Java 7, there are tools that can help solve this problem, if not at the level of the language, then at least not the level of crutches. So, the classes from the java.lang.invoke package will help us:

So, let's move on to the most interesting - how all this will help us. Now the code will look like this:
  1. import static java.lang.invoke.MethodHandles. *;
  2. import java.lang.invoke.MethodHandle;
  3. import java.lang.invoke.MethodType;
  4. class A {
  5. }
  6. class B extends A {
  7. }
  8. public class Test {
  9. public void call (A a) {
  10. System. out .println ( "A" );
  11. }
  12. public void call (b b) {
  13. System. out .println ( "B" );
  14. }
  15. public static void main ( String [] argv) {
  16. A b = new B ();
  17. Test test = new Test ();
  18. try {
  19. Lookup lookup = lookup ();
  20. MethodType mt = MethodType.methodType ( void . Class , b.getClass ());
  21. MethodHandle mh = lookup.findVirtual (Test. Class , "call" , mt);
  22. mh.invokeWithArguments (test, b);
  23. } catch (Throwable e) {
  24. e.printStackTrace ();
  25. }
  26. }
  27. }
* This source code was highlighted with Source Code Highlighter .

Let's see what happens here. In line 27 we declare directly the “search engine” of functions. Further, in line 28 we declare the types of the return value and parameters. It is important to note that the type of the return value is first passed to the methodType method, then the types of the parameter list of the desired method. Line 30 - we get in MethodHandle the search results for methods in the Test class, with the name call and the return value and mt parameter types. In line 31, we call the found method on the test object with the b parameter and see the expected “B” on the screen.

In the Lookup class, there are still quite a few methods, for example, to search for static functions, but the reader remains to study these features as homework.

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


All Articles