Java: доступ к приватному конструктору с параметрами типа - PullRequest
64 голосов
/ 12 апреля 2011

Это продолжение этого вопроса о частных конструкторах 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") используя отражение?

ОТВЕТ

Основано на ответе jtahlborn , следующие работы:

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);
    }   
}

Ответы [ 7 ]

44 голосов
/ 12 апреля 2011

Убедитесь, что вы используете 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);
28 голосов
/ 12 апреля 2011

вам нужно получить класс, найти конструктор, который принимает единственный аргумент с нижней границей T (в данном случае Object), заставить конструктор быть доступным (используя метод setAccessible) и, наконец, вызвать это с желаемым аргументом.

9 голосов
/ 12 апреля 2014

Хорошо, если частный конструктор не принимает никаких аргументов, мы получаем проблему при создании нового экземпляра, в этом случае после 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/

3 голосов
/ 13 апреля 2011

Как сказал @ArtB, вы можете использовать dp4j.com , , если знаете конструктор, который хотите использовать во время компиляции . На домашней странице проекта есть пример этого, доступ к конструктору Singleton.

Вместо @Test JUnit аннотируйте метод, с помощью которого можно внедрить 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, как в этот ответ .

2 голосов
/ 06 июня 2016

Если тестовый класс Junit (в тестовой папке) имеет то же имя пакета, что и у Actual Class, то из тестового примера Junit мы можем вызвать все закрытые методы для тестирования, без какой-либо дополнительной библиотеки, такой как dp4j.

1 голос
/ 12 апреля 2011

Существует библиотека для JUnit ( dp4j ), которая автоматически вставляет код для доступа к закрытым методам. Это может быть полезно.

0 голосов
/ 12 марта 2019

Сначала я получал NoSuchMethodException, используя отражение.

Используйте это:

Constructor<TestClass> constructor= (Constructor<TestClass>) TestClass.class.getDeclaredConstructors()[0];
...