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

84

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

你能访问类的私有构造函数并实例化它吗?

我回答'不可以',但是我的答案是错误的。

你能解释一下我错在哪里,并给出一个使用私有构造函数实例化对象的例子吗?


25
关于Java,大多数类似的面试问题可以回答:“是的,你几乎可以做任何事情,但你应该吗?一般来说,不应该!”就我个人而言,我认为这是一个愚蠢的问题。我不希望我的开发人员去做那些事情,所以我不在意他们是否知道如何做。更实际的语言细节应该更重要。了解反射的更一般的实用性可能已经足够了。理解面向对象设计模式和语言上的限制比那些应该避免的晦涩语言结构更重要。 - nicerobot
一个只有私有构造函数的类无法从外部实例化。这可以用于仅具有静态支持方法的类。(当然,您可以使用反射,但对于这样的类,这有什么意义呢。) - Daniel
今天我被问到了类似的问题,只不过是关于C#语言的。和你一样,我的回答也是“不行”,但是有一种方法可以访问私有构造函数,那就是使用一个公共静态方法来返回该构造函数,然后就可以在任何变量中(如我的var)存储私有构造函数的实例,而无需使用反射技术。 - ArCiGo
阅读此链接,我认为会对您有所帮助:https://dev59.com/A3M_5IYBdhLWcg3w2XPw - Fox
@Daniel Singleton除了getinstance之外,不需要静态方法。然后是在同一类中对实例的静态引用。其他所有内容都不需要是静态的。你所描述的是一个实用程序。 - Potato
显示剩余5条评论
21个回答

1
反射是Java中的一个API,我们可以使用它在运行时调用方法,而不管它们所使用的访问修饰符。 要访问类的私有构造函数:

我的实用类

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

我的测试类创建了一个Utility类的对象(示例)。
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会导致额外的开销问题。

0

是的,你可以使用反射来实例化一个私有构造函数的实例,下面是我从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();
    }
  }
}

首先将setAccessible设置为true,然后调用newInstance()方法。 c.setAccessible(true); c.newInstance(); - mahesh

0
我们可以在同一个类中创建createInstance(),从而创建私有类的实例,并通过在main()中使用类名调用相同的方法来实现:
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();

     }
}

0
还有另一种选择,可以创建getInstance()方法,在同一个类中创建私有构造函数的实例并返回该对象。
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();
    }
  }

0

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


1
单例模式使用私有构造函数,类外部无法实例化,但我们可以使用已经实例化的类。 - gmhk

0

简单的答案是,我们可以在Java中使用私有构造函数。

有各种情况下我们可以使用私有构造函数。主要的情况包括:

  • 内部构造函数链接
  • 单例类设计模式

0

我们无法在类外部访问私有构造函数,但是使用Java反射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容器还会创建并注入具有私有构造函数的类的对象。

0

我尝试了这样做,它可以工作。如果我错了,请给我一些建议。

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

}
}

0
拥有私有构造函数的基本前提是,私有构造函数限制了除自己类代码之外的其他代码访问该类对象的能力。
是的,我们可以在一个类中拥有私有构造函数,并且可以通过创建一些静态方法来使它们可访问,这些静态方法反过来会创建该类的新对象。
 Class A{
private A(){
}
private static createObj(){
return new A();
}

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

因此,要创建此类的对象,其他类必须使用静态方法。

当我们将构造函数设置为私有时,拥有静态方法的意义是什么?

静态方法存在的目的是,在需要创建该类的实例时,可以在创建实例之前应用一些预定义的检查。例如,在单例类中,静态方法会检查实例是否已经被创建。如果实例已经被创建,则只需返回该实例而不是创建新实例。

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

-1

你也可以查看该类是否还有其他公共构造函数。只因为默认构造函数是私有的,并不意味着你不能实例化该类。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接