我如何访问一个类的私有构造函数?

我是一名Java开发人员。 在一次采访中,我被问到一个关于私人构造函数的问题:

你可以访问一个类的私有构造函数并实例化它吗?

我回答“不”,但是错了。

你能解释我为什么错了,给一个实例化一个私有构造函数的对象的例子吗?

一种绕过限制的方法是使用reflection:

 import java.lang.reflect.Constructor; public class Example { public static void main(final String[] args) throws Exception { Constructor<Foo> constructor = Foo.class.getDeclaredConstructor(new Class[0]); constructor.setAccessible(true); Foo foo = constructor.newInstance(new Object[0]); System.out.println(foo); } } class Foo { private Foo() { // private! } @Override public String toString() { return "I'm a Foo and I'm alright!"; } } 
  • 你可以在类中使用它(例如在一个公共的静态工厂方法中)
  • 如果是嵌套类,则可以从封闭类访问它
  • 根据适当的权限,你可以用reflection来访问它

这些是否适用也不是很清楚 – 你能提供更多的信息吗?

这可以通过reflection来实现。

考虑一个具有私有构造函数的类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]); 

面试中有关私人build构者的第一个问题是,

我们可以在一个类中有私人构造函数吗?

有时,候选人给出的答案是,不,我们不能有私人build设者。

所以我想说, 是的,你可以在一个类中有私人的构造函数。

这并不是什么特别的事情,试着这样想,

私人:任何私人只能在课堂上访问。

构造器(Constructor):与类的名称相同的方法,创build类的对象时隐式调用。

或者你可以说,创build一个对象,你需要调用它的构造函数,如果构造函数没有被调用,那么对象不能被实例化。

这意味着,如果我们在一个类中有一个私有构造函数,那么它的对象只能在类中实例化。 所以用更简单的话来说,如果构造函数是私有的,那么你将不能在类之外创build它的对象。

有什么好处这个概念可以被实现来实现单例对象 (这意味着只能创build一个类的一个对象)。

看下面的代码,

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

是的,你可以像@Jon Steet所说的那样。

访问私有构造函数的另一种方法是在此类中创build一个公共静态方法,并将其返回types作为其对象。

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

使用javareflection如下:

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

您当然可以从同一个类和其内部类中的其他方法或构造函数访问私有构造函数。 使用reflection,你也可以在其他地方使用私有构造函数,前提是SecurityManager不会阻止你这样做。

看看Singleton模式。 它使用私有构造函数。

我喜欢上面的答案,但有两个更漂亮的方法来创build一个具有私有构造函数的类的新实例。 这一切都取决于你想要达到的目标以及在什么情况下。

1:使用Java工具和ASM

那么在这种情况下,你必须用变压器启动JVM。 要做到这一点,你必须实现一个新的Java代理,然后让这个变换器改变你的构造函数。

首先创build类变换器 。 这个类有一个叫做transform的方法。 重写这个方法,在这个方法里面,你可以使用ASM 类阅读器和其他类来操作构造函数的可见性。 转换完成后,您的客户端代码将可以访问构造函数。

您可以在这里阅读更多关于这个: 使用ASM更改私有Java构造函数

2:重写构造函数代码

那么,这不是真的访问构造函数,但仍然可以创build一个实例。 假设您使用了第三方库(比方说Guava),并且您可以访问代码,但是您不想更改由JVM加载的jar中的代码(我知道这是不是很逼真,但假设代码是在像Jetty这样的共享容器中,并且不能更改共享代码,但是你有单独的类加载上下文),那么你可以用私有构造函数创build第三方代码的副本,更改在您的代码中保护或公开的私有构造函数,然后将类放在类path的开头。 从这一点你的客户端可以使用修改后的构造函数和创build实例。

后一种变化被称为链接缝 ,这是一种接缝,其中使能点是类path。

那么,如果还有其他的公共构造函数,也可以。 仅仅因为无参数的构造函数是私人的,并不意味着你只是不能实例化类。

是的,您可以使用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(); } } } 

拥有一个私有构造函数的基本前提是拥有一个私有构造函数来限制自己的类代码以外的代码的访问,从而使得该类的对象成为可能。

是的,我们可以在一个类中有私有构造函数,是的,可以通过创build一些静态方法来创build新的对象。

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

所以要创build这个类的对象,其他类必须使用静态方法。

当我们构造函数是私有的时候,有一个静态方法是什么意思?

有静态方法,以便在需要创build该类的实例时,可以在创build实例之前,在静态方法中应用一些预定义的检查。 例如,在一个Singleton类中,静态方法检查实例是否已经被创build。 如果实例已经创build,那么它只是简单地返回该实例,而不是创build一个新实例。

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

是的,我们可以访问私有构造函数或者用私有构造函数实例化一个类。 javareflectionAPI和单例devise模式已经大量利用概念来访问私有构造函数。 此外,Spring框架容器可以访问bean的私有构造函数,并且此框架使用了JavareflectionAPI。 以下代码演示访问私有构造函数的方式。

 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[] = class.getDeclaredConstructor(); con[0].setAccessible(true); con[0].newInstance(null); }catch(Exception e){} } } output: private constructor invocation 

我希望你明白了。

你可以在类之外访问它的非常容易的访问只需要一个singaltan类的例子我们都做同样的事情使私人构造函数和通过静态方法访问实例这里是与您的查询相关联的代码

 ClassWithPrivateConstructor.getObj().printsomething(); 

它肯定会工作,因为我已经testing过了