Возможно ли в java создать «пустой» экземпляр класса без конструктора без аргументов с использованием отражения?

У меня есть класс, который не имеет конструктора по умолчанию. И мне нужен способ получить "пустой" экземпляр этого класса. «пусто» означает, что после создания экземпляра все поля класса должны иметь значения по умолчанию, такие как null, 0 и т. д.

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


person Vladimir    schedule 09.11.2010    source источник


Ответы (5)


Со стандартным отражением — нет, но есть библиотека, которая может сделать это за вас: objenesis.

Он специально разработан для создания экземпляров классов без конструкторов по умолчанию и используется другими библиотеками сериализации, такими как xstream.

Примечание. В этих случаях конструктор может не вызываться (но это, вероятно, то, что вам нужно).

person Brad Cupit    schedule 09.11.2010
comment
Согласен - очень зло. Когда программист не создает ctor, он ожидает, что его никто не вызовет, и - сюрприз! :-) - person iirekm; 09.11.2010
comment
Но, с другой стороны, обычное отражение также нарушает правила проектирования классов (например, доступ к приватным полям), но, по крайней мере, большинство программистов осознают, что такая вещь, как отражение, существует. Очень немногие программисты знают об objensis. - person iirekm; 09.11.2010
comment
Не особенно зло - очень полезно при реализации пользовательских схем сериализации, особенно когда исходный объект не реализован как сериализуемый. В .NET есть метод FormatterServices.GetUninitializedObject() как раз для этой цели. Я бы хотел, чтобы у Java было что-то подобное, официальное. - person Wayne Citrin; 25.06.2016
comment
да не особо зло, но с его помощью можно нарушить хотя бы одну из гарантий Java: jqno.nl/post/2015/02/28/hacking-java-enums - person Jordan; 28.08.2017

Наличие экземпляра класса в виде переменной clazz:

ReflectionFactory rf = ReflectionFactory.getReflectionFactory();
Constructor objDef = parent.getDeclaredConstructor();
Constructor intConstr = rf.newConstructorForSerialization(clazz, objDef);
clazz.cast(intConstr.newInstance());

как описано в http://www.javaspecialists.eu/archive/Issue175.html.

person mcveat    schedule 09.11.2010
comment
Хороший. У нас может быть победитель здесь! (+1) - person Sean Patrick Floyd; 09.11.2010
comment
Имейте в виду, однако, что класс ReflectionFactory является классом Sun, поэтому он будет работать только на виртуальных машинах Sun/Oracle, и даже тогда он может быть изменен. - person Francis Upton IV; 22.12.2011
comment
Откуда parent? - person Raffi Khatchadourian; 20.01.2017
comment
Это должен быть принятый ответ. У меня тоже такой же вопрос (как и у многих других матерей)... кто является/обеспечивает родителем...? или это список вызовов newConstructorForSerlialization вплоть до класса конструктора без аргументов, сериализуемого или нет? а затем просто заполнить созданные классы сериализованными данными? - person Ordiel; 14.01.2019
comment
Что касается parent - я думаю, что идея состоит в том, чтобы пропустить недоступный c'tor и вместо этого использовать c'tor одного из суперклассов, чтобы большая часть полей объекта была правильно инициализирована. Согласно ответу @jonstok, вы даже можете просто использовать c'tor по умолчанию Object. Главное, о чем я здесь беспокоюсь, - поля, о которых не знает предоставленный c'tor, инициализированы ли они нулями? - person Guss; 24.06.2020

Ваше решение будет специфичным для JVM.

Если вам нужно портативное решение, используйте стороннюю библиотеку.

Для Sun JVM v1.5 вы можете сделать это:

    final Class<?> myClass = MyClass.class;
    final ReflectionFactory reflection = ReflectionFactory.getReflectionFactory();
    final Constructor<Object> constructor = 
        reflection.newConstructorForSerialization(
            myClass, Object.class.getDeclaredConstructor(new Class[0]));
    final Object o = constructor.newInstance(new Object[0]);

    System.out.print(o.getClass());

Соответствующие классы в XStream:

  • com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider
  • com.thoughtworks.xstream.core.JVM;
person johnstok    schedule 09.11.2010
comment
Если я правильно понимаю, ваш код заставляет Sun ReflectionFactory использовать конструктор по умолчанию Object вместо недоступных конструкторов MyClass. Кажется, это работает, но остается вопрос: инициализируются ли поля MyClass нулями, когда не существует кода конструктора, который их знает? Я пытался следовать коду для ReflectionFactory, но он оказался слишком сложным для меня. - person Guss; 24.06.2020

Единственным решением, которое я могу придумать, было бы использование библиотеки манипулирования байт-кодом, такой как javassist, для добавления конструктора по умолчанию.

person Maurice Perry    schedule 09.11.2010

Если в вашем классе нет другого конструктора, компилятор создаст его за вас. У вас может быть конструктор без аргументов, но вы этого не понимаете.

Если вы не напишете конструктор без аргументов и включите даже один конструктор, принимающий аргумент, компилятор не даст вам его. Рефлексия тоже не поможет: если вы попытаетесь найти конструктор без аргументов, а его нет, что вы ожидаете?

Не похоже, что вы можете использовать сериализацию объектов Java с помощью java.lang.Serializable, но это не единственный выбор. Вы также можете использовать XML, или JSON, или буферы прототипов, или любой другой удобный протокол.

person duffymo    schedule 09.11.2010
comment
+1 за то, что он (почти) единственный, кто знает, о чем он (и ОП) говорит - person Sean Patrick Floyd; 09.11.2010
comment
Небезопасно не было варианта в 2010 году, когда был опубликован этот вопрос. Это функция JDK 9: javaworld.com/ статья/2952869/java-платформа/ - person duffymo; 12.09.2017