2017-02-01 4 views
2

Есть ли способ ссылаться на группу методов в Java 8, которая меняет свою подпись на перегрузку?Ссылки на методы в Java 8: поддерживается ли перегрузка?

Точнее, я хотел бы этот код для работы:

public class OverloadingMethodRef 
{ 
    public static void foo (int x) { 
     System.out.println ("An integer: " + x); 
    } 

    public static void foo (String x) { 
     System.out.println ("A String: " + x); 
    } 

    /** 
    * I want it to work without this 
    */ 
// public static void foo (Object x) { 
//  if (x instanceof Integer) foo ((int) x); else foo ((String) x); 
// } 

    public static void main (String[] args) 
    { 
     // Compile error, it wants a precise reference to one of them 
     Consumer<Object> c = PolymorphicMethodRef::foo; 
     foo ("bla"); // despite it could get it 
     foo (1); // and here too 
    } 
} 

Я не могу позволить, чтобы добавить public static void foo (Object x), потому что у меня есть много способов, чтобы перейти к другому методу, и я не хочу писать оберток. До сих пор я мог делать это только через отражение (которое может принимать param.getClass()), но методы, которые я должен вызывать, имеют разные аргументы (> = 1) и каждый раз, когда мне нужно помещать их в массив, а также их типы в другом.

+3

Поддерживается полиморфизм. А также нет - это не полиморфизм, это перегрузка **. И нет, нет - Java-метод вызывает вызовы для конкретных перегрузок метода во время компиляции. –

+0

Whops! Да, я имею в виду перегрузку, я задал вопрос, спасибо. – zakmck

+1

Это действительно невозможно получить ссылку на метод, которая будет действовать так, как если бы она указывала на перегруженный метод. Лучше всего вы можете добавить еще один метод, например 'void foo (Object x)', и вывести его из этого, но он все равно всегда будет называть этот точный метод (с параметром Object) и никогда не решится ни на что другое. –

ответ

5

Ссылки на методы поддерживают перегрузку с использованием тех же правил, что и при обычных вызовах метода. Если у вас есть Consumer<Object>, вы можете передавать произвольные Object экземпляры его метода accept, то есть вы можете написать

Consumer<Object> c = /* some expression producing it*/; 
c.accept(new JButton()); 
// or just 
c.accept(new Object()); 

и так как вы не можете писать

foo(new JButton()); 
// or 
foo(new Object()); 

, когда у вас есть только foo(int) и foo(String), это также невозможно написать

Consumer<Object> c = OverloadingMethodRef::foo; 

который бы построить Consumer делает вид, что принимает произвольные Object экземпляров.

Если вы готовы принять Reflection накладных расходов, вы можете использовать

Consumer<Object> c=o -> { 
    try { 
     new Statement(OverloadingMethodRef.class, "foo", new Object[]{o}).execute(); 
    } catch (Exception ex) { 
     throw new RuntimeException(ex); 
    } 
}; 
c.accept(42); 
c.accept("bla"); 

(это относится к java.beans.Statement)

Конечно, это может потерпеть неудачу во время выполнения при его вызове с неподдерживаемым аргументом тип.

+0

Спасибо @Holger. На практике этого не хватает на Java :-) Я понимаю, что он соответствует проверке статического типа, но все же не очень хорош (прием произвольного объекта, привязка во время выполнения и повышение предупреждения во время компиляции были бы лучше для меня). Re: отражение, я использую 'org.apache.commons.lang3.reflect.MethodUtils', более простой синтаксис. – zakmck

Смежные вопросы