Как создать объект с помощью LambdaMetaFactory?

У меня есть действие интерфейса:

package action;

public interface Action {
    public String act();
}

Класс SimpleAction:


package action;

public class SimpleAction implements Action {

    String action;
    public SimpleAction() {}

    public SimpleAction(String x) {
        this.action = x;
    }

    @Override
    public String act() {
        return "Act method from -" + this.action;
    }
}

Класс ComplexAction:



    package action;

    public class ComplexAction implements Action{

        String action;
        public ComplexAction() {}
        public ComplexAction(String x) {
            this.action = x;
        }
        @Override
        public String act() {
            return "Act method from -" + this.action;
        }
    }

Я хочу создать функцию, которая берет имя класса и возвращает объект этого класса. Это то, что у меня есть до сих пор в моей функции -

 

    public static Action resultOfActMethod(String objclass){   
        Class clazz = Class.forName(objclass);
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodHandle mh = lookup.findConstructor(clazz,MethodType.methodType(void.class, String.class));
    }


person John Doe    schedule 07.12.2018    source источник


Ответы (2)


Догадаться.

public static Action resultOfActMethod(String objclass){    
    Class clazz = Class.forName(objclass);
    MethodHandles.Lookup lookup = MethodHandles.lookup();
    MethodHandle mh = lookup.findConstructor(clazz, MethodType.methodType(void.class, String.class));
    Function<String, Action> constructor = (Function<String, Action>)LambdaMetafactory.metafactory(lookup, "apply",MethodType.methodType(Function.class),
                        mh.type().generic(), mh, mh.type()).getTarget().invokeExact();
    Action action = constructor.apply(objclass);
    return action;
}
person John Doe    schedule 07.12.2018

Вы можете сделать именно это, он даст вам объект, используя конструктор без аргументов:

public static Object resultOfActMethod(String objclass) 
    throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
  Class<?> clazz = Class.forName(objclass);
  return clazz.getConstructor().newInstance();
}

Но если это возможно в вашем приложении, вы должны создать функцию, которая принимает класс, например:

public static <C> C resultOfActMethod(Class<C> clazz) 
    throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
  return clazz.getConstructor().newInstance();
}

Это типобезопасно. Вы можете использовать определенный тип возврата. Это позволит избежать приведения типа на стороне вызывающего абонента.

person Donat    schedule 07.12.2018
comment
Ссылаясь на документ Java, я не думаю, что разумно использовать этот подход. В javadoc специально говорится, что использование этого метода эффективно обходит проверку исключений во время компиляции, которая в противном случае выполнялась бы компилятором. Метод Constructor.newInstance позволяет избежать этой проблемы, заключая любое исключение, созданное конструктором, в (проверенное) исключение InvocationTargetException. - person John Doe; 07.12.2018
comment
Благодаря Google, StackOverflow и небольшим исследованиям я смог решить эту проблему. Я разместил свой ответ ниже. - person John Doe; 08.12.2018
comment
Автор этого вопроса специально запросил ответ, связанный с LambdaMetafactory, стандартный пример отражения не следует давать. - person Maowcraft; 24.07.2021