Как я могу получить доступ к частному конструктору класса? - PullRequest
63 голосов
/ 08 апреля 2010

Я разработчик Java.В одном из интервью мне задали вопрос о частных конструкторах:

Можете ли вы получить доступ к частному конструктору класса и создать его экземпляр?

Я ответил «Нет», но былнеправильно.

Можете ли вы объяснить, почему я ошибался, и привести пример создания объекта с помощью частного конструктора?

Ответы [ 18 ]

79 голосов
/ 08 апреля 2010

Один из способов обойти ограничение - использовать отражения:

import java.lang.reflect.Constructor;

public class Example {
    public static void main(final String[] args) throws Exception {
        Constructor<Foo> constructor = Foo.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        Foo foo = constructor.newInstance();
        System.out.println(foo);
    }
}

class Foo {
    private Foo() {
        // private!
    }

    @Override
    public String toString() {
        return "I'm a Foo and I'm alright!";
    }
}
67 голосов
/ 08 апреля 2010
  • Вы можете получить к нему доступ внутри самого класса (например, в общедоступном статическом методе фабрики)
  • Если это вложенный класс, вы можете получить к нему доступ из класса
  • При условии наличия соответствующих разрешений вы можете получить к нему доступ с помощью отражения

Не совсем понятно, применимо ли какое-либо из них - можете ли вы дать больше информации?

19 голосов
/ 08 апреля 2010

Это может быть достигнуто с помощью отражения.

Рассмотрим класс Test с приватным конструктором:

Constructor<?> constructor  = Test.class.getDeclaredConstructor(Context.class, String[].class);
Assert.assertTrue(Modifier.isPrivate(constructor.getModifiers()));
constructor.setAccessible(true);
Object instance = constructor.newInstance(context, (Object)new String[0]);
6 голосов
/ 23 июня 2014

Самый первый вопрос, который задают в отношении частных конструкторов в интервью:

Можем ли мы иметь частного конструктора в классе?

И иногда ответ, который даеткандидат: нет, у нас не может быть частных конструкторов.

Поэтому я хотел бы сказать, Да, у вас могут быть частные конструкторы в классе.

Это не особенныйвещь, попробуйте думать об этом так,

Личное: Все, что личное, может быть доступно только из класса.

Конструктор: методимя которого совпадает с именем класса, и оно неявно вызывается при создании объекта класса.

или вы можете сказать, что для создания объекта вам необходимо вызвать его конструктор, если конструктор не вызывается, тогда объектне может быть создан.

Это означает, что если у нас есть закрытый конструктор в классе, то его объекты могут быть созданы только внутри класса.Таким образом, вы можете сказать более простыми словами: если конструктор является закрытым, вы не сможете создавать его объекты вне класса.

В чем выгода Эта концепция может быть реализована для достижения объект singleton (это означает, что может быть создан только один объект класса).

См. Следующий код,

class MyClass{
    private static MyClass obj = new MyClass();

    private MyClass(){

    }

    public static MyClass getObject(){
        return obj;
    }
}
class Main{
    public static void main(String args[]){

        MyClass o = MyClass.getObject();
        //The above statement will return you the one and only object of MyClass


        //MyClass o = new MyClass();
        //Above statement (if compiled) will throw an error that you cannot access the constructor.

    }
}

Теперь сложная часть, почему вы ошиблисьКак уже объяснялось в других ответах, вы можете обойти ограничение, используя Reflection.

4 голосов
/ 09 июня 2016

Использование java Reflection следующим образом:

   import java.lang.reflect.Constructor;

   import java.lang.reflect.InvocationTargetException;

   class Test   
   {

      private Test()  //private constructor
      {
      } 
   }

  public class Sample{

      public static void main(String args[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException
     {

       Class c=Class.forName("Test"); //specify class name in quotes

       //----Accessing private constructor
       Constructor con=c.getDeclaredConstructor();
       con.setAccessible(true);     
       Object obj=con.newInstance();
   }   
} 
3 голосов
/ 25 июня 2014

Да, вы могли бы, как упомянул @Jon Steet.

Еще один способ получить доступ к закрытому конструктору - создать открытый статический метод внутри этого класса и иметь возвращаемый тип в качестве объекта.

public class ClassToAccess
{

    public static void main(String[] args)
    {
        {
            ClassWithPrivateConstructor obj = ClassWithPrivateConstructor.getObj();
            obj.printsomething();
        }

    }

}

class ClassWithPrivateConstructor
{

    private ClassWithPrivateConstructor()
    {
    }

    public void printsomething()
    {
        System.out.println("HelloWorld");
    }

    public static ClassWithPrivateConstructor getObj()
    {
        return new ClassWithPrivateConstructor();
    }
}
3 голосов
/ 02 июля 2016

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

1: использование инструментария Java и ASM

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

Сначала создайте преобразователь класса . Этот класс имеет метод с именем transform. Переопределите этот метод, и внутри этого метода вы можете использовать ASM читатель класса и другие классы для управления видимостью вашего конструктора. После завершения преобразования ваш клиентский код получит доступ к конструктору.

Подробнее об этом можно прочитать здесь: Изменение частного конструктора Java с помощью ASM

2: переписать код конструктора

Ну, это на самом деле не доступ к конструктору, но все же вы можете создать экземпляр. Давайте предположим, что вы используете стороннюю библиотеку (скажем, Guava) и у вас есть доступ к коду, но вы не хотите изменять этот код в банке, которая по какой-то причине загружается JVM (я знаю, это не очень реалистично, но давайте предположим, что код находится в общем контейнере, таком как Jetty, и вы не можете изменить общий код, но у вас есть отдельный контекст загрузки класса), тогда вы можете сделать копию стороннего кода с помощью частного конструктора, изменить закрытый конструктор для защищенного или общедоступного в вашем коде, а затем поместите ваш класс в начало пути к классам. С этого момента ваш клиент может использовать модифицированный конструктор и создавать экземпляры.

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

2 голосов
/ 10 июля 2017

Да, мы можем получить доступ к приватному конструктору или создать экземпляр класса с помощью приватного конструктора. API отражения java и шаблон проектирования Singleton широко используют концепцию для доступа к частному конструктору. Кроме того, контейнеры фреймворка Spring могут обращаться к частному конструктору bean-компонентов, и этот фреймворк использует API отражения java. Следующий код демонстрирует способ доступа к приватному конструктору.

class Demo{
     private Demo(){
      System.out.println("private constructor invocation");
     }
}

class Main{
   public static void main(String[] args){
       try{
           Class class = Class.forName("Demo");
           Constructor<?> con = string.getDeclaredConstructor();
           con.setAccessible(true);
           con.newInstance(null);
       }catch(Exception e){}

   }
}

output:
private constructor invocation

Надеюсь, ты понял.

2 голосов
/ 08 апреля 2010

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

0 голосов
/ 11 января 2019

Простой ответ: да, мы можем иметь частные конструкторы в Java .

Существуют различные сценарии, в которых мы можем использовать частные конструкторы.Основные из них:

  • Внутренняя цепочка конструктора
  • Шаблон проектирования класса Singleton
...