Ответ 1
вам нужно будет получить класс, найти конструктор, который принимает один аргумент с нижней границей T (в данном случае Object), заставить конструктор быть доступным (используя метод setAccessible
) и, наконец, вызвать с нужным аргументом.
Это продолжение этого вопроса о частных конструкторах java.
Предположим, что у меня есть следующий класс:
class Foo<T>
{
private T arg;
private Foo(T t) {
// private!
this.arg = t;
}
@Override
public String toString() {
return "My argument is: " + arg;
}
}
Как бы я построил new Foo("hello")
с помощью отражения?
ANSWER
На основе jtahlborn answer, следующие работы:
public class Example {
public static void main(final String[] args) throws Exception {
Constructor<Foo> constructor;
constructor = Foo.class.getDeclaredConstructor(Object.class);
constructor.setAccessible(true);
Foo<String> foo = constructor.newInstance("arg1");
System.out.println(foo);
}
}
вам нужно будет получить класс, найти конструктор, который принимает один аргумент с нижней границей T (в данном случае Object), заставить конструктор быть доступным (используя метод setAccessible
) и, наконец, вызвать с нужным аргументом.
Удостоверьтесь, что вы используете getDeclaredConstructors
при получении конструктора и устанавливаете его доступность к true с его частной.
Что-то вроде этого должно работать.
Constructor<Foo> constructor= (Constructor<Foo>) Foo.class.getDeclaredConstructors()[0];
constructor.setAccessible(true);
Foo obj = constructor.newInstance("foo");
System.out.println(obj);
Обновление
Если вы хотите использовать getDeclaredConstructor, передайте Object.class в качестве аргумента, который переводит на общий T.
Class fooClazz = Class.forName("path.to.package.Foo");
Constructor<Foo> constructor = fooClazz.getDeclaredConstructor(Object.class);
constructor.setAccessible(true);
Foo obj = constructor.newInstance("foo");
System.out.println(obj);
Хорошо, если частный конструктор не принимает никаких аргументов, мы получаем проблему при создании нового экземпляра, в этом случае после setAccessible true мы не можем создать объект.
Даже construct.newInstance(null);
не будет создавать объект без конструктора аргументов.
мы можем создать объект ниже кода с использованием отражения:
public class Singleton {
private static Singleton instance = new Singleton();
/* private constructor */
private Singleton() {}
public static Singleton getDefaultInstance() {
return instance;
}
}
Да, мы можем создать объект выше класса.
// reflection concept to get constructor of a Singleton class.
Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
// change the accessibility of constructor for outside a class object creation.
constructor.setAccessible(true);
// creates object of a class as constructor is accessible now.
Singleton secondOb = constructor.newInstance();
// close the accessibility of a constructor.
constructor.setAccessible(false);
Вы можете обратиться: Пример 2: "Яркая инициализация" и "Синглтонное нарушение отражением" в моем блоге: http://sanjaymadnani.wordpress.com/2014/04/14/singleton-design-pattern-in-java/
Как @ArtB сказал, что вы можете использовать dp4j.com, , если знаете конструктор, который вы хотите использовать во время компиляции. На главной странице проекта есть пример именно этого, доступ к конструктору Singleton.
Вместо JUnit @Test аннотируйте метод, в котором нужно ввести Reflection с помощью @Reflect:
public class Example {
@com.dp4j.Reflect
public static void main(final String[] args){
Foo<String> foo = new Foo("hello");
System.out.println(foo);
}
}
Чтобы увидеть, что сгенерированный код отражения использовал -Averbose = true аргумент, как в этот ответ.
Если класс тестирования Junit (в тестовой папке) имеет то же имя пакета, что и для Actual Class, то из теста Junit Test мы можем вызвать все частные методы для тестирования без какой-либо дополнительной библиотеки, такой как dp4j.
Существует библиотека для JUnit (dp4j), которая автоматически вставляет код для доступа к приватным методам. Это может быть полезно.