Вызов самого обтягивающего метода

Как часть разработки небольшого ScriptEngine, я отражающим образом называю методы Java. Вызов механизмом выполнения сценария дает мне объект имя метода и массив аргументов. Для вызова метода, я пытался разрешить его с вызовом к Class.getMethod (имя, типы аргумента).
Это однако только работает, когда классы аргументов и классы, ожидаемые Методом, являются тем же.

Object o1 = new Object();
Object out = System.out;
//Works as System.out.println(Object) is defined
Method ms = out.getClass().getMethod("println",o1.getClass());
Object o2 = new Integer(4);
//Does not work as System.out.println(Integer) is not defined
Method mo = out.getClass().getMethod("println",o2.getClass());

Я хотел бы знать, существует ли "простой" способ получить правильный метод, если это возможно, с самым близким пригодным для типов аргумента, или если я должен реализовать это сам.

Самое близкое соответствие было бы:

Object o1 = new Integer(1);
Object o2 = new String("");
getMethod(name, o1.getClass())//println(Object)
getMethod(name, o2.getClass())//println(String)  

Обновление:
Для разъяснения то, в чем я нуждаюсь: Механизм выполнения сценария является маленьким проектом, который я пишу в свое свободное время, таким образом, нет никаких строгих правил, за которыми я должен следовать. Таким образом, я думал, что выбор методов, названных от Механизма тем же путем, компилятор Java выбирает методы во время компиляции только с динамическим типом, а не статический тип Объекта работал бы. (с или не автоупаковывая)
Это - то, что я сначала надеялся, что Class.getMethod () решит. Но Class.getMethod () требует тех же самых Классов как типы аргумента, как Метод объявляет, использование подкласса не приведет ни к какому такому Исключению метода. Это может произойти на серьезных основаниях, но делает метод бесполезным для меня, поскольку я не знаю заранее, какие типы аргумента соответствовали бы.
Альтернатива должна была бы назвать Class.getMethods () и выполнить итерации через возвращенный массив и попытаться найти подходящий метод. Это однако было бы сложно, если я только хочу взять первый "хороший" метод, с которым я сталкиваюсь, таким образом, я надеялся, что будет существующее решение, которое, по крайней мере, обрабатывает:

  • самое близкое соответствие: Если arg.getClass () == подкласс и методы m (Суперкласс), m (Подкласс) затем называют m (Подкласс)
  • аргументы переменной: System.out.printf (Строка, Строка...)

Поддержка автоупаковки была бы хороша, также.
Если вызов не может быть разрешен, он может выдать исключение (мама (Строка, Объект), мама (Объект, Строка), args = Строка, Строка)
(Если Вы сделали его до здесь, благодарит занять время для чтения it:-)),

5
задан josefx 9 February 2010 в 09:07
поделиться

3 ответа

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

Вероятно, имеет смысл как можно точнее следовать правилам разрешения перегрузки javac:
http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#292575
Вы, вероятно, можете игнорировать обобщения для языка сценариев с динамической типизацией, но вы все равно можете извлечь выгоду из методов моста , которые компилятор генерирует автоматически.

Некоторые подводные камни, на которые следует обратить внимание:

  • Class.isAssignableFrom не знает об автоматических расширяющихся примитивных преобразованиях, потому что это синтаксический сахар, реализованный в компиляторе; Они не встречаются в виртуальной машине или иерархии классов. например int.class.isAssignableFrom (short.class) возвращает false .
  • Аналогично Class.isAssignableFrom не знает об автобоксе. Integer.class.isAssignableFrom (int.class) возвращает false .
  • Class.isInstance и Class.cast принимают в качестве аргумента объект ; Им нельзя передавать примитивные значения. Они также возвращают объект , поэтому их нельзя использовать для распаковки ( (int) new Integer (42) разрешен в исходном коде Java, но int.class.cast (new Целое число (42)) вызывает исключение.)
2
ответ дан 14 December 2019 в 19:12
поделиться

AFAIK, нет простого способа сделать такие вещи. Конечно, в стандартных библиотеках классов Java для этого нет ничего.

Проблема в том, что не существует однозначного «правильного» ответа. Вам необходимо рассмотреть все варианты использования, решить, каким должен быть «правильный метод», и соответствующим образом реализовать свой код отражения.

1
ответ дан 14 December 2019 в 19:12
поделиться

Я бы посоветовал вам использовать getMethods () . Он возвращает массив всех общедоступных методов ( Method [] ).

Самая важная вещь здесь:
" Если класс объявляет несколько общедоступных методов-членов с одинаковыми типами параметров, все они включаются в возвращаемый массив. "

Что вам нужно сделать, так это использовать результаты в этом массиве, чтобы определить , какой из них (если есть) является наиболее близким. Поскольку наиболее близкое соответствие во многом зависит от ваших требований и конкретного приложения, имеет смысл кодировать его самостоятельно.


Пример кода, иллюстрирующий один из подходов к этому:

public Method getMethod(String methodName, Class<?> clasz)
{
    try
    {
        Method[] methods = clasz.getMethods();
        for (Method method : methods)
        {
            if (methodName.equals(method.getName()))
            {
                Class<?>[] params = method.getParameterTypes();
                if (params.length == 1)
                {
                    Class<?> param = params[0];
                    if ((param == int.class) || (param == float.class) || (param == float.class))
                    {
                        //method.invoke(object, value);
                        return method;
                    }
                    else if (param.isAssignableFrom(Number.class))
                    {
                        return method;
                    }
                    //else if (...)
                    //{
                    //    ...
                    //}
                }
            }
        }
    }
    catch (Exception e)
    {
        //some handling
    }
    return null;
}

В этом примере метод getMethod (String, Class ) возвращает метод, который имеет только один параметр который является int , float , double или суперклассом Number .

Это элементарная реализация. Она возвращает первый метод, отвечающий всем требованиям. Вам нужно будет расширить его, чтобы создать список всех подходящих методов, а затем отсортировать их по каким-то критериям и вернуть метод наилучшего соответствия.

Затем вы можете пойти еще дальше, создав более общий метод getMethod (String, Class ) для обработки большего количества возможных сценариев «близкого соответствия» и, возможно, даже более одного paramter

HTH


Изменить: как указал @finnw, будьте осторожны при использовании Class # isAssignableFrom (Class cls) из-за его ограничений, как у меня в моем примере кода , тестируя примитивы отдельно от объектов Number .

2
ответ дан 14 December 2019 в 19:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: