How can I access a private constructor of a class?

2019-01-16 15:20发布

I am a Java developer. In an interview I was asked a question about private constructors:

Can you access a private constructor of a class and instantiate it?

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?

18条回答
Bombasti
2楼-- · 2019-01-16 16:03

This can be achieved using reflection.

Consider for a class Test, with a private constructor:

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]);
查看更多
迷人小祖宗
3楼-- · 2019-01-16 16:03

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

Well in this case you have to start the JVM with a transformer. To do this you have to implement a new Java agent and then make this transformer change the constructor for you.

First create the class transformer. This class has a method called 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. 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

2: Rewrite the constructor code

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. 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.

查看更多
Summer. ? 凉城
4楼-- · 2019-01-16 16:03

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.

查看更多
地球回转人心会变
5楼-- · 2019-01-16 16:05

Using java Reflection as follows :

   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楼-- · 2019-01-16 16:10

Yes you could, as mentioned by @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();
    }
}
查看更多
可以哭但决不认输i
7楼-- · 2019-01-16 16:11

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.

查看更多
登录 后发表回答