我是一名Java开发人员。在面试中,我被问到一个关于私有构造函数的问题:
你能访问类的私有构造函数并实例化它吗?
我回答'不可以',但是我的答案是错误的。
你能解释一下我错在哪里,并给出一个使用私有构造函数实例化对象的例子吗?
我是一名Java开发人员。在面试中,我被问到一个关于私有构造函数的问题:
你能访问类的私有构造函数并实例化它吗?
我回答'不可以',但是我的答案是错误的。
你能解释一下我错在哪里,并给出一个使用私有构造函数实例化对象的例子吗?
绕过限制的一种方法是使用反射:
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!";
}
}
但并不清楚这些是否适用 - 您能提供更多信息吗?
可以使用反射来实现这一点。
考虑一个具有私有构造函数的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]);
在面试中关于私有构造函数被问到的第一个问题是:
一个类中能否有私有构造函数?
而有时候应聘者给出的答案是:不,我们不能有私有构造函数。
所以我想说:是的,你可以在一个类中拥有私有构造函数。
这并没有什么特别的,试着这样思考一下:
私有:任何私有内容只能从类内部访问。
构造函数:一个与类名相同的方法,当创建该类的对象时会自动调用。
或者说,要创建一个对象就需要调用它的构造函数,如果没有调用构造函数,则无法实例化对象。
这意味着,如果一个类中有私有构造函数,则其对象只能在类内部实例化。简单地说,如果构造函数是私有的,那么你就无法在类外创建它的对象。
好处是:
这个概念可以用来实现单例对象(也就是只能创建一个类对象)。
看下面的代码:
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.
}
}
现在是棘手的部分,为什么你是错的,就像其他答案已经解释过的那样,您可以使用反射绕过限制。
您可以在此处阅读更多信息: 使用ASM更改私有Java构造函数
嗯,这并不是真正访问构造函数,但仍然可以创建实例。假设您使用第三方库(比如Guava),您可以访问该代码,但由于某些原因您不想更改JVM加载的jar中的代码(我知道,这不太现实,但假设代码在像Jetty这样的共享容器中,您无法更改共享代码,但您有单独的类加载上下文),那么您可以将带有私有构造函数的第三方代码复制一份,将您代码中的私有构造函数更改为受保护或公共,并将您的类放在类路径的开头。从那时起,您的客户端就可以使用修改后的构造函数并创建实例。
后一种更改称为链接接缝,它是一种启用点为类路径的接缝。
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();
}
}
正如@Jon Steet所提到的那样,您可以这样做。
访问私有构造函数的另一种方法是在该类中创建一个public static方法,并将其返回类型设置为其对象。
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();
}
}
是的,我们可以访问私有构造函数或实例化具有私有构造函数的类。Java反射API和单例设计模式经常利用这个概念来访问私有构造函数。 另外,Spring框架容器可以访问bean的私有构造函数,并且该框架使用了Java反射API。 以下代码演示了访问私有构造函数的方法。
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
当然,您可以从同一类及其内部类的其他方法或构造函数中访问私有构造函数。使用反射,您还可以在其他地方使用私有构造函数,前提是SecurityManager没有阻止您这样做。
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();
}
}
}
输出: 私有构造函数已调用
var
)存储私有构造函数的实例,而无需使用反射技术。 - ArCiGo