it-roy-ru.com

Как я могу получить доступ к частному конструктору класса?

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

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

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

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

58
gmhk

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

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!";
    }
}
75
Joachim Sauer
  • Вы можете получить к нему доступ внутри самого класса (например, в общедоступном статическом методе фабрики)
  • Если это вложенный класс, вы можете получить к нему доступ из включающего класса
  • При условии наличия соответствующих разрешений вы можете получить к нему доступ

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

67
Jon Skeet

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

Рассмотрим для класса 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]);
19
tonio

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

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

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

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

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

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

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

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

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

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

Смотрите следующий код,

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.

    }
}
6
gprathour

Используя 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();
   }   
} 
4
kalyani chaudhari

Да, вы могли бы, как упомянул @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
Tapeshvar

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

2
jarnbjo

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

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

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

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

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

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

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

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

2
Captain Fogetti

Да, мы можем получить доступ к приватному конструктору или создать экземпляр класса с помощью приватного конструктора. 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
Sushan Baskota

Посмотрите на шаблон синглтона. Он использует приватный конструктор.

0
3biga

Я надеюсь, что этот пример может помочь вам:

package MyPackage;

import Java.lang.reflect.Constructor;

/**
 * @author Niravdas
 */

class ClassWithPrivateConstructor {

    private ClassWithPrivateConstructor() {
        System.out.println("private Constructor Called");
    }

}
public class InvokePrivateConstructor 
{
     public static void main(String[] args) {
        try
        {
           Class ref = Class.forName("MyPackage.ClassWithPrivateConstructor");
           Constructor<?> con = ref.getDeclaredConstructor();
           con.setAccessible(true);
           ClassWithPrivateConstructor obj = (ClassWithPrivateConstructor) con.newInstance(null);
       }catch(Exception e){
           e.printStackTrace();
       }
    }

}

Результат: Закрытый конструктор

0
Niravdas

Мы не можем получить доступ к приватному конструктору за пределами класса, но используя Java Reflection API, мы можем получить доступ к приватному конструктору. Пожалуйста, найдите ниже код:

public class Test{
    private Test()
    System.out.println("Private Constructor called");
}
}


public class PrivateConsTest{
    public void accessPrivateCons(Test test){

        Field[] fields = test.getClass().getDeclaredFields();

        for (Field field : fields) {
            if (Modifier.isPrivate(field.getModifiers())) {
                field.setAccessible(true);
                System.out.println(field.getName()+" : "+field.get(test));
            }
        }
    }
}

Если вы используете Spring IoC, контейнер Spring также создает и внедряет объект класса, имеющий закрытый конструктор. 

0
Vishwanath Kumar

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

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

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

Я пытался, как это работает. Дайте мне предложение, если я ошибаюсь.

import Java.lang.reflect.Constructor;

class TestCon {
private TestCon() {
    System.out.println("default constructor....");
}

public void testMethod() {
    System.out.println("method executed.");
  }
}

class TestPrivateConstructor {

public static void main(String[] args) {
    try {
        Class testConClass = TestCon.class;
        System.out.println(testConClass.getSimpleName());

        Constructor[] constructors =    testConClass.getDeclaredConstructors();
        constructors[0].setAccessible(true);
        TestCon testObj = (TestCon) constructors[0].newInstance();
        //we can call method also..
        testObj.testMethod();
    } catch (Exception e) {
        e.printStackTrace();
    }

}
}
0
Lokendra solanki

Да, вы можете создать экземпляр с помощью закрытого конструктора, используя Reflection , см. Пример, который я вставил ниже, взятый из Java2s , чтобы понять, как:

import Java.lang.reflect.Constructor;
import Java.lang.reflect.InvocationTargetException;

class Deny {
  private Deny() {
    System.out.format("Deny constructor%n");
  }
}

public class ConstructorTroubleAccess {
  public static void main(String... args) {
    try {
      Constructor c = Deny.class.getDeclaredConstructor();
      // c.setAccessible(true); // solution
      c.newInstance();

      // production code should handle these exceptions more gracefully
    } catch (InvocationTargetException x) {
      x.printStackTrace();
    } catch (NoSuchMethodException x) {
      x.printStackTrace();
    } catch (InstantiationException x) {
      x.printStackTrace();
    } catch (IllegalAccessException x) {
      x.printStackTrace();
    }
  }
}
0
madx

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

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

 Class A{
private A(){
}
private static createObj(){
return new A();
}

Class B{
public static void main(String[]args){
A a=A.createObj();
}}

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

Какой смысл иметь статический метод, когда мы делаем конструктор закрытым?

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

 public static MySingleTon getInstance(){
    if(myObj == null){
        myObj = new MySingleTon();
    }
    return myObj;
}
0
Nikhil Arora