Передать производный объект в метод, требующий суперкласса, используя отражение Java?

РЕДАКТИРОВАТЬ: Я не понял. Мне нужно использовать отражение, потому что я интерпретирую из командной строки. Я делаю отражение, эквивалентное приведенным мною примерам кода.

надеюсь, что это не дубликат, потому что это кажется повседневным занятием.

У меня есть класс A и класс B, расширяющий A. Если у меня есть метод класса C, например public void doSomething (A a), как я могу использовать отражение для передачи объекта B в эту функцию? Я хочу сделать (отражение) эквивалент:

B b = new B(); //B inherits from A
C c = new C();
c.doSomething(b); // method signature is doSomething(A a);

Я сделал (используя отражение):

  1. получил объекты, которые являются аргументами функции.
  2. получить классы аргументов
  3. найти метод на основе классов аргументов.
  4. вызывают метод, передавая ему аргумент Objects.

Это отлично работает, если я собираюсь передать объект A в C.doSomething (...). Однако, если я пытаюсь передать объект B в C.doSomething (...), на шаге 3 возникает ошибка:

java.lang.NoSuchMethodException: C.doSomething (B)

Что такое подходящий способ заставить C.doSomething распознать, что B - это A? (при поиске метода с использованием getDeclaredMethod (String name, Class ... parameterTypes) и передаче B.class в качестве типа параметра)

РЕДАКТИРОВАТЬ:

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

String methodToken; //the name of the method
Object obj; //the object whose method we are trying to call
Object[] args; //the user given arguments for the method
Class[] argTypes; //the types of the args gotten by args[i].getClass();

так что ...

    //*** try to get the specified method from the object


    Method m = null;

    // if we are looking for a no-arg version of the method:
    if(null == args)
    {
        try
        {
            m = obj.getClass().getMethod(methodToken, argTypes);
        }
        catch ( /*errors*/ )
        {
            // do stuff
        }
    }
    else // if we are looking for a version of the method that takes arguments
    {
        // we have to do this type of lookup because our user arguments could be 
        // subclasses of the arguments required by the method. getMethod will not
        // find a match in that case.
        try
        {
            boolean matchFound = false;
            Class c = obj.getClass();
            do
            {   // for each level in the inheritance hierarchy:

                // get all the methods with the right name 
                //(matching the name that the user supplied for the method)
                Method[] methodList = c.getMethods();
                ArrayList<Method> matchingMethods = new ArrayList<Method>();
                for( Method meth : methodList)
                {
                    if(meth.getName().equals(methodToken))
                    {
                        matchingMethods.add(meth); 
                    }
                }

                // check for a matching method signature
                for( Method meth : matchingMethods)
                {
                    // get the types of the arguments the method under
                    // investigation requires.
                    Class[] paramList = meth.getParameterTypes();

                    // make sure the signature has the required number of 
                    // elements. If not, this is not the correct method.
                    if(paramList.length != args.length)
                    {
                        continue;
                    }


                    // Now check if each method argument is assignable from the
                    // type given by the user's provided arguments. This means
                    // that we are checking to see if each of the user's 
                    // arguments is the same as, or is a superclass or 
                    // superinterface of the type found in the method signature
                    //(i.e. it is legal to pass the user arguments to this 
                    // method.) If one does not match, then this is not the 
                    // correct method and we continue to the next one.

                    boolean signatureMatch = false;
                    for ( int i = 0; i < paramList.length; ++i)
                    {
                        if(paramList[i].isAssignableFrom( argTypes[i] ) )
                        {
                            signatureMatch = true;
                        }
                        else
                        {
                            continue;
                        }
                    }


                    // if we matched the signature on a matchingly named
                    // method, then we set the method m, and indicate 
                    // that we have found a match so that we can stop
                    // marching up the inheritance hierarchy. (i.e. the
                    // containing loop will terminate.
                    if(true == signatureMatch)
                    {
                        m = meth;
                        matchFound = true;
                        break;
                    }

                }

                // move up one level in class hierarchy.
                c = c.getSuperclass();
            }
            while(null != c && false == matchFound);
        }
        catch( /*errors*/)
        {
            // do stuff
        }
    }

    // check that m got assigned
    if(null == m)
    {
        System.out.println("From DO: unable to match method");
        return false;
    }

    // try to invoke the method !!!!
    try
    {
        m.invoke(obj, args);
    }
    catch ( /* errors */ )
    {
        // do stuff
    }

Надеюсь, это когда-нибудь поможет кому-то!

6
задан ROMANIA_engineer 11 August 2016 в 14:43
поделиться