Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java generics: actual argument T cannot be converted to int by method invocation conversion

Tags:

java

generics

I have a code like this:

// This class cannot be changed
class VendorApi {
        static void func1(char x) {}
        static void func1(int x) {}
        static void func1(float x) {}
        static void func1(double x) {}
}

class Main {
          static <T> void my_func(T arg) {
                  // much of code, which uses T
                  // ...
                  VendorApi.<T>func1(arg);
          }

          public static void main(String args[]) {
                  // call my_func for each type (char, int, float, double)
                  // ...
                  int i = 1;
                  my_func(i);
                  char c = 1;
                  my_func(c);
          }
}

What I need to do is to call every function VendorApi.func() for every type of argument from my_func(). The code posted does not compile, it shows an idea. How can I do it besides copy-pasting my_func() for every type?

like image 738
Gennady Proskurin Avatar asked Jan 23 '15 11:01

Gennady Proskurin


2 Answers

You could pass func1 into the method as a Consumer<T>:

class VendorApi {
    static void func1(char x) {}
    static void func1(int x) {}
    static void func1(float x) {}
    static void func1(double x) {}
}

class Main {
      static void my_func(char arg) {  my_func(arg, VendorApi::func1); }
      static void my_func(int arg) {  my_func(arg, VendorApi::func1); }
      static void my_func(float arg) {  my_func(arg, VendorApi::func1); }
      static void my_func(double arg) {  my_func(arg, VendorApi::func1); }
      private static <T> void my_func(T arg, Consumer<T> func1) {
          // much of code, which uses T
          // ...
          func1.accept(arg);
      }

      public static void main(String args[]) {
          // call my_func for each type (char, int, float, double)
          // ...
          int i = 1;
          my_func(i, VendorApi::func1);
          char c = 1;
          my_func(c);
      }
}

This gives you compile time type safety (you can only call my_func with char, int, float and double from outside of the class since the generic version is private) and avoids reflection.

Also my_func should be myFunc if you want to follow the Java method naming conventions.

like image 154
Alex - GlassEditor.com Avatar answered Oct 24 '22 13:10

Alex - GlassEditor.com


Not the cleanest answer, but it will do what you ask.

You can test whether your generic arguments class matches with any of the types that your VenderApi provides and then cast is.

Code

public class Main {
    static <T> void my_func(T arg) {
        if (arg.getClass().equals(Integer.class))
            VendorApi.func1((Integer) arg);
        else if (arg.getClass().equals(Character.class))
            VendorApi.func1((Character) arg);
        else
            throw new IllegalStateException(
                    "cannot perform my_func on object of class "
                            + arg.getClass());
    }

    public static void main(String args[]) {
        // call my_func for each type (char, int, float, double)
        // ...
        int i = 1;
        my_func(i);
        char c = 1;
        my_func(c);
        String str = "bla";
        my_func(str);
    }
}

your vendor API

//This class cannot be changed
public class VendorApi {
    public static void func1(char x) {
        System.out.println("i am a char "+x);
    }

    public static void func1(int x) {
        System.out.println("i am a int "+x);
    }

    public static void func1(float x) {
    }

    public static void func1(double x) {
    }
}

Output

i am a int 1
i am a char 
Exception in thread "main" java.lang.IllegalStateException: cannot perform my_func on object of class class java.lang.String
    at core.Main.my_func(Main.java:10)
    at core.Main.main(Main.java:23)
like image 26
Niels Billen Avatar answered Oct 24 '22 11:10

Niels Billen