Использование отражения в Java для установки параметров метода - PullRequest
1 голос
/ 30 апреля 2019

Я пытаюсь достичь чего-то, приближающегося к следующему:

public class MyClass<E>
{
    protected MyClass(Object[] variables)
    {
        //init
    }

    public MyClass(Comparator<? super E> comp, Object[] variables)
    {
        //init
    }

    public static <K extends Comparable<? super K>, T extends MyClass<K>> 
         T construct(T example, Object[] variables)
    {
        return new T(variables);
    }
}

Где переменные Object [] - это не фактический код, а скорее заполнитель для любых фактических параметров построения.

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

Меня не особо волнует, использует ли решение отражение или нет, пока оно работает, но отражение показалось наиболее вероятным вариантом.

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

Edit: Из-за обратной связи, что нет возможности динамически установить параметры construct() Я хотел бы немного изменить вопрос.

Предполагая, что защищенный конструктор имеет необходимые параметры для построения класса, если я использую vararg (public static <K extends Comparable<? super K>, T extends MyClass<K>> T construct(T example, Object... variables)), что будет лучшим способом гарантировать, что аргументы, передаваемые в переменные, соответствуют параметрам, требуемым для конструктора? Я надеялся сделать это динамически, потому что тогда сам компилятор предотвратил бы такие проблемы, но без этой возможности я прошу лучшее альтернативное решение.

Редактировать: Для пояснения, это моя настоящая цель: я хочу, чтобы MyClass принял либо параметризацию E, которая расширяет Comparable или любую параметризацию, но передал Comparator в Я могу достичь второй цели просто через конструктор, но чтобы оставить E открытым для любого варианта во втором случае, я должен оставить его открытым для любого варианта в целом. Чтобы справиться с этим, я сделал общий конструктор защищенным и сделал открытый статический метод для принудительной реализации Comparable и выступил в качестве псевдо-конструктора с типом возвращаемого значения MyClass, где K - Comparable. Однако это вызывает проблемы, когда другой класс расширяет MyClass. Если я заранее знаю, что наследуемый класс будет иметь те же параметры, что и MyClass, то я могу просто скрыть метод и соответственно изменить тип возвращаемого значения. Но если я хочу, чтобы у подкласса были другие параметры, я изменил сигнатуру метода и больше не могу использовать его, чтобы скрыть предыдущий, а это означает, что подкласс может возвращать не только свой экземпляр, но и совершенно другой экземпляр своего родителя. Это то, чего я бы хотел избежать.

Ответы [ 3 ]

0 голосов
/ 30 апреля 2019

Не думаю, что вам нужно размышлять. Вам просто нужно упростить то, что вам нужно, и использовать мощь Java и дженерики для своих нужд. Вот пример вашего третьего редактирования:

class MyClass<E> {
    private Comparator<MyClass<E>> comparator;

    public MyClass(List<Object> params, Comparator<MyClass<E>> comparator) {
        //init
        this.comparator = comparator;
    }

}
class  MyClassExtension extends MyClass<Integer> {

    public MyClassExtension(List<Object> params, Comparator<MyClass<java.lang.Integer>> comparator) {
        super(params, comparator);
    }
}
class  MyClassExtension2<E> extends MyClass<E> {

    public MyClassExtension2(List<Object> params, Comparator<MyClass<E>> comparator) {
        super(params, comparator);
    }
}
0 голосов
/ 30 апреля 2019

Я думаю, что мог реализовать потенциальное решение самостоятельно, хотя я хотел бы получить отзыв о его жизнеспособности.

public class MyClass<E>
{
    public MyClass(Comparable<? super E> example, E example2, Object[] variables) 
      throws IllegalArgumentException
    {
        if(!example.getClass().equals(example2.getClass())
        {
             throw new IllegalArgumentException();
        }
        //init
    }

    public MyClass(Comparator<? super E> comp, Object[] variables)
    {
        //init
    }
}

Идея состоит в том, что оператор if заставляет example быть одним и тем жекласс как универсальный E, а наличие example в качестве параметра заставляет этот класс реализовать Comparable.

0 голосов
/ 30 апреля 2019

Это может сработать, но я бы не советовал. Обратите внимание, чтобы это работало example и все члены variables ДОЛЖНЫ БЫТЬ не null

public static <K extends Comparable<? super K>, T extends MyClass<K>> 
     T construct(T example, Object[] variables) throws 
                 NoSuchMethodException,
                 SecurityException,
                 InstantiationException,
                 IllegalAccessException,
                 IllegalArgumentException,
                 InvocationTargetException 
{
    Objects.requireNotNull(example);

    Class<?>[] argTypes = new Class<?>[variables.length];
    for ( int i = 0; i < variables.length; ++i)
    {
        // This will NPE if variables[i] is null
        argTypes[i] = variables[i].getClass();
    }

    // This will throw, if constructor is not defined
    Constructor<?> constructor = example.getClass().getConstructor(argTypes);

    return (T) constructor.newInstance(variables);
}

Обычно то, что вы делаете, может быть достигнуто созданием интерфейса Factory, который создает экземпляры определенного класса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...