2012-06-19 3 views
3

У меня есть метод fooКак вызвать полиморфную функцию из агностической функции?

void foo (String x) { ... } 
void foo (Integer x) { ... } 

, и я хочу, чтобы вызвать из метода, который не заботится об аргументе:

void bar (Iterable i) { 
    ... 
    for (Object x : i) foo(x); // this is the only time i is used 
    ... 
} 

код выше жалуется на то что foo(Object) не определен и когда добавить

void foo (Object x) { throw new Exception; } 

затем bar(Iterable<String>) вызовы, которые вместо foo(String) и беспересадочный исключение.

Как избежать двух текстовых идентичных определений bar(Iterable<String>) и bar(Iterable<Integer>)?

Я думал, что я мог бы сойти с рук что-то вроде

<T> void bar (Iterable<T> i) { 
    ... 
    for (T x : i) foo(x); // this is the only time i is used 
    ... 
} 

, но затем я получаю cannot find foo(T) ошибку.

+0

возможно дубликата HTTP: // stackoverflow.com/questions/4086523/patterns-to-compensate-for-lack-of-runtime-method-lookup-based-on-polymorphic-ar – Alex

ответ

1

Думайте об этом так: какую версию foo следует называть, если x является Object?

Это проблема, с которой сталкивается JVM.

Если вы хотите действительно полиморфный метод, вам нужно явно написать его. Такой метод мог бы затем осмотреть Object с помощью интроспекции, чтобы узнать, что это за тип фактического класса, и вызвать соответствующий метод после этого.

Или, вы можете взглянуть на то, что делает foo. Это только методы вызова, определяемые Object? Если это так, просто создайте метод void foo(Object x), который выполняет необходимые действия.

2

Проблема, с которой вы сталкиваетесь, заключается в том, что перегруженные методы связаны во время компиляции. В вашем примере компилятор пытается выяснить, какой из методов foo() для вызова. Однако самым сильным статическим типом x в вашем примере является Object, и нет метода foo(Object), поэтому компилятор говорит, что он не может вызвать соответствующий метод.

Если вы добавите метод foo(Object), независимо от того, каков фактический тип времени выполнения x, вы всегда будете называть метод foo(Object).

Эта проблема распространяется на использование дженериков. Поскольку T может быть любого типа, у вас должен быть общий метод foo(T), или ваш код не будет компилироваться. Однако, если вы добавите этот метод, вы потеряете способность распознавать эти методы между разными типами аргументов, потому что будет вызываться только foo(T).

Единственный способ обойти это - это сделать случайную проверку и бросить, как и другие предложенные ответы. Если типы аргументов не являются классами, которые вы определяете, и все они могут реализовать общий интерфейс.Затем вы можете сделать что-то вроде:

interface ArgumentType { 
    void callback(FooClass c); 
} 

class YourClassA implements ArgumentType { 
    void callback(FooClass c) { 
     c.foo(this); 
    } 
} 

FooClass еще будет иметь метод foo() для каждого реализующего класса ArgumentType, но таким образом, вы можете иметь свой выбор по типу агностика.

+0

Не могли бы вы объяснить, что вы подразумеваете под «самым сильным статическим типом»? Благодаря! – Miquel

+1

«Самый сильный статический тип» Я имею в виду наиболее специфический тип, который компилятор может сделать для вашей переменной x. Например, в принципе, если у вас есть этот код: Object x; x = новый Integer(); Foo (х); умный компилятор может понять, что тип x на сайте вызова является Integer и может вызвать соответствующий метод. В вашем примере это невозможно, потому что нечего намекать на тип вашего кода. Следовательно, «самый сильный» тип, который компилятор знает, - это Object. – Jochen

+0

Спасибо за объяснение! – Miquel

1

Проблема заключается в том, что вы пытаетесь найти foo(Object x), и хотя String и Integer являются объектами, не все объекты являются либо строковыми, либо целыми, а java не ограничивает класс.

я бы, возможно, предлагаю создать метод, как:

void foo(Object o){ 
    if (o instanceof String){ 
     String s = (String) o; 
     //Deal with s 
    } else if (o instanceof Integer){ 
     Integer i = (Integer) o; 
     //Deal with i 
    } 
} 

Кроме того, если вы используете генерик в любом случае, вы не должны быть пропусканием сырца итератора в баре

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