Подтвердить что ты не робот

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

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

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

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

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

4b9b3361

Ответ 1

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

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!";
    }
}

Ответ 2

  • Вы можете получить доступ к нему внутри самого класса (например, в общедоступном статическом методе factory)
  • Если это вложенный класс, вы можете получить к нему доступ из класса-оболочки
  • При наличии соответствующих разрешений вы можете получить доступ к нему с отражением

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

Ответ 3

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

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

Ответ 4

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

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

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

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

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

Приватный: все, что приватно, доступно только из класса.

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

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

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

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

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

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.

Ответ 5

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

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

Ответ 6

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

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

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

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

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

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

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

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

Ответ 7

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

Ответ 8

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

Ответ 9

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

Я надеюсь, что вы получили это.

Ответ 10

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

Ответ 11

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

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

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

Ответ 12

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

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

}

Вывод: частный конструктор называется

Ответ 13

Мы не можем получить доступ к приватному конструктору вне класса, но используя 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 также создает и внедряет объект класса, имеющий закрытый конструктор.

Ответ 14

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

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

}
}

Ответ 15

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

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

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

Ответ 16

Reflection - это API в java, который мы можем использовать для вызова методов во время выполнения независимо от спецификатора доступа, используемого с ними. Чтобы получить доступ к частному конструктору класса:

My utility class

public final class Example{
    private Example(){
        throw new UnsupportedOperationException("It is a utility call");
    }
    public static int twice(int i)
    {
        int val = i*2;
        return val;
    }
}

My Test class which creates an object of the Utility class(Example)

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
class Test{
    public static void main(String[] args) throws Exception {
        int i =2;
        final Constructor<?>[] constructors = Example.class.getDeclaredConstructors();
        constructors[0].setAccessible(true);
        constructors[0].newInstance();
    }
}

При вызове конструктора он выдаст ошибку java.lang.UnsupportedOperationException: It is a utility call

Но помните, что использование отражения API вызывает проблемы с накладными расходами

Ответ 17

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

Ответ 18

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

Ответ 19

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

ClassWithPrivateConstructor.getObj().printsomething();

он будет определенно работать, потому что я уже тестировал