简体   繁体   English

如何访问 class 的私有构造函数?

[英]How can I access a private constructor of a class?

I am a Java developer.我是 Java 开发人员。 In an interview I was asked a question about private constructors:在一次采访中,我被问到一个关于私有构造函数的问题:

Can you access a private constructor of a class and instantiate it?您可以访问 class 的私有构造函数并实例化它吗?

I answered 'No' but was wrong.我回答“否”,但我错了。

Can you explain why I was wrong and give an example of instantiating an object with a private constructor?你能解释为什么我错了,并举一个用私有构造函数实例化 object 的例子吗?

One way to bypass the restriction is to use reflections: 绕过限制的一种方法是使用反射:

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!";
    }
}
  • You can access it within the class itself (eg in a public static factory method) 您可以在类本身内访问它(例如,在公共静态工厂方法中)
  • If it's a nested class, you can access it from the enclosing class 如果它是嵌套类,则可以从封闭类访问它
  • Subject to appropriate permissions, you can access it with reflection 根据适当的权限,您可以使用反射访问它

It's not really clear if any of these apply though - can you give more information? 现在还不清楚这些是否适用 - 你能提供更多信息吗?

This can be achieved using reflection. 这可以使用反射来实现。

Consider for a class Test, with a private constructor: 考虑使用私有构造函数的类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]);

The very first question that is asked regarding Private Constructors in Interviews is, 关于访谈中私人建筑商的第一个问题是,

Can we have Private constructor in a Class? 我们可以在一个类中拥有私有构造函数吗?

And sometimes the answer given by the candidate is, No we cannot have private constructors. 而有时候候选人给出的答案是,不,我们不能拥有私人建设者。

So I would like to say, Yes you can have private Constructors in a class. 所以我想说, 是的,你可以在课堂上拥有私人建筑师。

It is no special thing, try to think it this way, 这没什么特别的,试着这样想,

Private: anything private can be accessed from within the class only. 私人:私人的任何东西都只能在课堂上访问。

Constructor: a method which has same name as that of class and it is implicitly called when object of the class is created. 构造函数:一个与类名相同的方法,在创建类的对象时隐式调用它。

or you can say, to create an object you need to call its constructor, if constructor is not called then object cannot be instantiated. 或者你可以说,要创建一个你需要调用它的构造函数的对象,如果没有调用构造函数,那么就无法实例化对象。

It means, if we have a private constructor in a class then its objects can be instantiated within the class only. 这意味着,如果我们在一个类中有一个私有构造函数,那么它的对象只能在类中实例化。 So in simpler words you can say, if the constructor is private then you will not be able to create its objects outside the class. 因此,用简单的话来说,如果构造函数是私有的,那么你将无法在类之外创建它的对象。

What's the benefit This concept can be implemented to achieve singleton object (it means only one object of the class can be created). 有什么好处这个概念可以用来实现单例对象 (这意味着只能创建一个类的对象)。

See the following code, 请参阅以下代码,

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.

    }
}

Now the tricky part, why you were wrong, as already explained in other answers, you can bypass the restriction using Reflection. 现在是棘手的部分,为什么你错了,正如在其他答案中已经解释的那样,你可以使用Reflection绕过限制。

Using java Reflection as follows : 使用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();
   }   
} 

I like the answers above, but there are two more nifty ways of creating a new instance of a class which has private constructor. 我喜欢上面的答案,但是有两种更好的方法可以创建一个具有私有构造函数的类的新实例。 It all depends on what you want to achieve and under what circumstances. 这一切都取决于你想要达到的目标以及在什么情况下。

1: Using Java instrumentation and ASM 1:使用Java检测ASM

Well in this case you have to start the JVM with a transformer. 那么在这种情况下你必须用变压器启动JVM。 To do this you have to implement a new Java agent and then make this transformer change the constructor for you. 为此,您必须实现一个新的Java代理,然后使此转换器为您更改构造函数。

First create the class transformer . 首先创建类变换器 This class has a method called transform. 这个类有一个名为transform的方法。 Override this method and inside this method you can use the ASM class reader and other classes to manipulate the visibility of your constructor. 重写此方法,在此方法中,您可以使用ASM 类阅读器和其他类来操纵构造函数的可见性。 After the transformer is done, your client code will have access to the constructor. 变换器完成后,您的客户端代码将可以访问构造函数。

You can read more about this here: Changing a private Java constructor with ASM 您可以在此处阅读更多相关信息: 使用ASM更改私有Java构造函数

2: Rewrite the constructor code 2:重写构造函数代码

Well, this is not really accessing the constructor, but still you can create an instance. 好吧,这不是真正访问构造函数,但仍然可以创建一个实例。 Let's assume that you use a third-party library (let's say Guava) and you have access to the code but you don't want to change that code in the jar which is loaded by the JVM for some reason (I know, this is not very lifelike but let's suppose the code is in a shared container like Jetty and you can't change the shared code, but you have separate class loading context) then you can make a copy of the 3rd party code with the private constructor, change the private constructor to protected or public in your code and then put your class at the beginning of the classpath. 假设您使用第三方库(比如Guava)并且您可以访问代码,但是您不希望在由JVM加载的jar中更改该代码(我知道,这是不是很逼真但是假设代码在像Jetty这样的共享容器中,你不能改变共享代码,但你有单独的类加载上下文)那么你可以用私有构造函数复制第三方代码,改变在您的代码中保护或公开的私有构造函数,然后将您的类放在类路径的开头。 From that point your client can use the modified constructor and create instances. 从那时起,您的客户端可以使用修改后的构造函数并创建实例。

This latter change is called a link seam , which is a kind of seam where the enabling point is the classpath. 后一种变化称为链接接缝 ,它是一种接缝,其中使能点是类路径。

Yes you could, as mentioned by @Jon Steet. 是的,就像@Jon Steet所说的那样。

Another way of accessing a private constructor is by creating a public static method within this class and have its return type as its object. 访问私有构造函数的另一种方法是在此类中创建一个公共静态方法,并将其返回类型作为其对象。

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

You can of course access the private constructor from other methods or constructors in the same class and its inner classes. 您当然可以从同一类及其内部类中的其他方法或构造函数访问私有构造函数。 Using reflection, you can also use the private constructor elsewhere, provided that the SecurityManager is not preventing you from doing so. 使用反射,您也可以在其他地方使用私有构造函数,前提是SecurityManager没有阻止您这样做。

Yes, we can access the private constructor or instantiate a class with private constructor. 是的,我们可以访问私有构造函数或使用私有构造函数实例化一个类。 The java reflection API and the singleton design pattern has heavily utilized concept to access to private constructor. java反射API和单例设计模式大量利用概念来访问私有构造函数。 Also, spring framework containers can access the private constructor of beans and this framework has used java reflection API. 此外,spring框架容器可以访问bean的私有构造函数,并且此框架使用了java反射API。 The following code demonstrate the way of accessing the private constructor. 以下代码演示了访问私有构造函数的方法。

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

I hope you got it. 我希望你明白了。

I hope This Example may help you : 我希望这个例子可以帮助你:

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

}

Output: private Constructor Called 输出:私有构造函数调用

Yes you can instantiate an instance with a private constructor using Reflection , see the example I pasted below taken from java2s to understand how: 是的,您可以使用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();
    }
  }
}

The basic premise for having a private constructor is that having a private constructor restricts the access of code other than own class' code from making objects of that class. 拥有私有构造函数的基本前提是拥有私有构造函数限制除了自己的类代码之外的代码访问,从而使该类的对象成为可能。

Yes we can have private constructors in a class and yes they can be made accessible by making some static methods which in turn create the new object for the class. 是的,我们可以在类中使用私有构造函数,是的,可以通过创建一些静态方法来访问它们,这些方法又为类创建新对象。

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

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

So to make an object of this class, the other class has to use the static methods. 因此,要创建此类的对象,另一个类必须使用静态方法。

What is the point of having a static method when we are making the constructor private? 当我们将构造函数设为私有时,有一个静态方法有什么意义?

Static methods are there so that in case there is a need to make the instance of that class then there can be some predefined checks that can be applied in the static methods before creation of the instance. 静态方法是存在的,以便在需要创建该类的实例时,可以在创建实例之前在静态方法中应用一些预定义的检查。 For example in a Singleton class, the static method checks if the instance has already been created or not. 例如,在Singleton类中,静态方法检查实例是否已经创建。 If the instance is already created then it just simply returns that instance rather than creating a new one. 如果已经创建了实例,那么它只是简单地返回该实例而不是创建新实例。

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

We can not access private constructor outside the class but using Java Reflection API we can access private constructor. 我们无法访问类外的私有构造函数,但使用Java Reflection API我们可以访问私有构造函数。 Please find below code: 请找到以下代码:

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

If you are using Spring IoC, Spring container also creates and injects object of the class having private constructor. 如果您使用的是Spring IoC,Spring容器还会创建并注入具有私有构造函数的类的对象。

I tried like this it is working. 我试过这样的工作。 Give me some suggestion if i am wrong. 如果我错了,请给我一些建议。

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

}
}

Simple answer is yes we can have private constructors in Java . 简单的答案是肯定的,我们可以在Java中拥有私有构造函数。

There are various scenarios where we can use private constructors. 在各种情况下我们可以使用私有构造函数。 The major ones are 主要是

  • Internal Constructor chaining 内部构造函数链接
  • Singleton class design pattern Singleton类设计模式

Reflection is an API in java which we can use to invoke methods at runtime irrespective of access specifier used with them. Reflection是java中的API,我们可以使用它在运行时调用方法,而不管它们使用的访问说明符。 To access a private constructor of a class: 要访问类的私有构造函数:

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

When calling the constructor it will give the error java.lang.UnsupportedOperationException: It is a utility call 在调用构造函数时,它将给出错误java.lang.UnsupportedOperationException: It is a utility call

But remember using reflection api cause overhead issues 但请记住使用反射api导致开销问题

We can create instance of private class by creating createInstance() in the same class and simply call the same method by using class name in main() :我们可以通过在相同的 class 中创建 createInstance() 来创建私有 class 的实例,并通过在main()中使用 class 名称来简单地调用相同的方法:

class SampleClass1{
        private SampleClass1() {
            System.out.println("sampleclass cons");
        }
        public static void createInstance() {
            SampleClass1 sc = new SampleClass1();
        }
    }

public class SingletonDemo {
    public static void main(String[] args) {
        //SampleClass1 sc1 = new SampleClass1();
        SampleClass1.createInstance();

     }
}

Also have another option create the getInstance() where we can create instance of private constructor inside same class and return that object.还有另一个选项创建 getInstance(),我们可以在同一个 class 中创建私有构造函数的实例并返回该 object。

class SampleClass1{
        private SampleClass1() {
            System.out.println("sample class constructor");
        }
        public static SampleClass1 getInstance() {
            SampleClass1 sc1 = new SampleClass1();
            return sc1;
        }
    }
    public class SingletonDemo {
    public static void main(String[] args) {
        SampleClass1 obj1 = SampleClass1.getInstance();
    }
  }

Look at Singleton pattern. 看看Singleton模式。 It uses private constructor. 它使用私有构造函数。

Well, you can also if there are any other public constructors. 好吧,如果还有其他公共构造函数,你也可以。 Just because the parameterless constructor is private doesn't mean you just can't instantiate the class. 仅仅因为无参数构造函数是私有的并不意味着你只是无法实例化该类。

you can access it outside of the class its very easy to access just take an example of singaltan class we all does the same thing make the private constructor and access the instance by static method here is the code associated to your query 你可以在类之外访问它非常容易访问只是举一个singaltan类的例子我们都做同样的事情使私有构造函数和静态方法访问实例这里是与你的查询相关的代码

ClassWithPrivateConstructor.getObj().printsomething();

it will definately work because i have already tested 它肯定会起作用,因为我已经测试过了

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在具有私有构造函数的 class 中使用 @Value 或 autowire 环境? - How can I use @Value or autowire Environment in a class with private constructor? 如何从测试类中访问私有方法 - how can I access a private method from the test class 如何在Java中访问私有类成员? - How can I access private class members in Java? 如何访问私有包类的公共成员? - How can I access public member of private package class? 如何获得对父类的私有变量的访问权限? - How can I gain access to a parent class's private variable? 当类只有一个私有构造函数时,如何创建代理? - How can I create a proxy when the class having only one private constructor? 如何使用反射创建具有私有字段和构造函数的类对象? - How can I make an object of class having private fields and constructor using reflection? 为什么如果我将其默认构造函数声明为private,则无法将其子类化 - why a class can not be subclassed if i declare its default constructor as private 如何访问匿名内部类中容器类的私有类成员? - How can I access private class members of container class within the anonymouse inner class? 在java中,如何使用私有构造函数创建一个类,其超类也有一个私有构造函数? - In java, how do I make a class with a private constructor whose superclass also has a private constructor?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM