Java: newInstance класса, у которого нет конструктора по умолчанию - PullRequest
39 голосов
/ 09 сентября 2010

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

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

Заранее спасибо.

Ответы [ 6 ]

49 голосов
/ 09 сентября 2010

Вызовите Class.getConstructor(), а затем Constructor.newInstance(), передав соответствующие аргументы. Пример кода:

import java.lang.reflect.*;

public class Test {

    public Test(int x) {
        System.out.println("Constuctor called! x = " + x);
    }

    // Don't just declare "throws Exception" in real code!
    public static void main(String[] args) throws Exception {
        Class<Test> clazz = Test.class;
        Constructor<Test> ctor = clazz.getConstructor(int.class);
        Test instance = ctor.newInstance(5);           
    }
}
6 голосов
/ 14 февраля 2013

Вот общее решение, которое не требует javassist или другого байт-кода «манипулятор».Хотя предполагается, что конструкторы не делают ничего, кроме простого присвоения аргументов соответствующим полям, поэтому он просто выбирает первый конструктор и создает экземпляр со значениями по умолчанию (т. Е. 0 для int, ноль для Object и т.1002 *

PS Работает с Java 1.5+.В решении также предполагается, что не существует менеджера SecurityManager, который мог бы предотвратить вызов f.setAccessible(true).

2 голосов
/ 09 сентября 2010

Если вы не использовали фальшивые фреймворки (например, ezmock), я настоятельно рекомендую вам попробовать.

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

Редактировать: в ответ на комментарий.

Нет, современные фальшивые фреймворки позволяют вам создавать «фальшивый» экземпляр любого класса из «ничего» и передавать его, как если бы он был экземпляром класса. Ему не нужен интерфейс,это может быть любой класс. Также могут быть написаны методы для возврата последовательности значений из простого всегда возврата «7» в «При вызове с аргументом arg = 7 возвращаем 5 первого вызова, 6 второго и 7 третьего».

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

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

1 голос
/ 28 января 2014

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

protected List<Object> FillObject(ResultSet rs, String className)
    {
        List<Object> dList = new ArrayList<Object>();

        try
        {
            ClassLoader classLoader = GenericModel.class.getClassLoader();

            while (rs.next())
            {
                Class reflectionClass = classLoader.loadClass("models." + className);

                Object objectClass = reflectionClass.newInstance();

                Method[] methods = reflectionClass.getMethods();

                for(Method method: methods)
                {
                    if (method.getName().indexOf("set") > -1)
                    {
                        Class[] parameterTypes = method.getParameterTypes();

                        for(Class pT: parameterTypes)
                        {
                            Method setMethod = reflectionClass.getMethod(method.getName(), pT);

                            switch(pT.getName())
                            {
                                case "int":
                                    int intValue = rs.getInt(method.getName().replace("set", ""));
                                    setMethod.invoke(objectClass, intValue);
                                    break;

                                case "java.util.Date":
                                    Date dateValue = rs.getDate(method.getName().replace("set", ""));
                                    setMethod.invoke(objectClass, dateValue);
                                    break;

                                case "boolean":
                                    boolean boolValue = rs.getBoolean(method.getName().replace("set", ""));
                                    setMethod.invoke(objectClass, boolValue);
                                    break;

                                default:
                                    String stringValue = rs.getString(method.getName().replace("set", ""));
                                    setMethod.invoke(objectClass, stringValue);
                                    break;
                            }
                        }
                    }
                }

                dList.add(objectClass);
            }
        }
        catch (Exception e)
        {
            this.setConnectionMessage("ERROR: reflection class loading: " + e.getMessage());
        }

        return dList;
    }
0 голосов
/ 09 сентября 2010

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

Тогда вашей программе тестирования не нужно использовать рефлексию. Просто создайте экземпляр класса AssignmentFactory и вызовите метод make с правильными аргументами.

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

package assignment ;

public class AssignmentFactory
{
     public AssignmentFactory ( )
     {
           super ( ) ;
     }

     public AssignmentFactory make ( .... parameters )
     {
           return new Assignment ( .... arguments ) ;
     }
}
0 голосов
/ 09 сентября 2010

Вы можете использовать Class.getConstructor или Class.getConstructors , а затем использовать метод Constructor.newInstance для инициализации объекта, который вы хотите использовать.

...