我是一名Java开发人员。在一次采访中,我被问到一个关于私人建设者的问题:
您可以访问类的私有构造函数并实例化它吗?
我回答'不',但错了。
你能解释一下为什么我错了,举一个用私有构造函数实例化对象的例子吗?
答案 0 :(得分:76)
绕过限制的一种方法是使用反射:
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!";
}
}
答案 1 :(得分:67)
现在还不清楚是否有任何适用 - 你能提供更多信息吗?
答案 2 :(得分:19)
这可以通过反射来实现。
考虑使用私有构造函数的类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]);
答案 3 :(得分:5)
关于访谈中私人建筑商的第一个问题是,
我们可以在Class中使用Private构造函数吗?
有时候候选人给出的答案是,不,我们不能拥有私人建设者。
所以我想说,是的,你可以在课堂上拥有私人建筑师。
这不是特别的事情,试着这样想,
私人:只能在班级内访问任何私密内容。
构造函数:一个与类名相同的方法,并在创建类的对象时隐式调用它。
或者你可以说,要创建一个你需要调用它的构造函数的对象,如果没有调用构造函数,那么就无法实例化对象。
这意味着,如果我们在一个类中有一个私有构造函数,那么它的对象只能在类中实例化。因此,用简单的话来说,如果构造函数是私有的,那么你将无法在类之外创建它的对象。
有什么好处 可以实现此概念以实现单例对象(这意味着只能创建该类的一个对象)。
请参阅以下代码
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.
}
}
现在棘手的部分,为什么你错了,正如在其他答案中已经解释的那样,你可以使用反射绕过限制。
答案 4 :(得分:4)
使用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();
}
}
答案 5 :(得分:3)
是的,你可以,正如@Jon Steet所说。
访问私有构造函数的另一种方法是在此类中创建一个公共静态方法,并将其返回类型作为其对象。
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();
}
}
答案 6 :(得分:3)
我喜欢上面的答案,但是有两种更好的方法可以创建一个具有私有构造函数的类的新实例。这一切都取决于你想要达到的目标以及在什么情况下。
在这种情况下,您必须使用变换器启动JVM。为此,您必须实现一个新的Java代理,然后让这个转换器为您更改构造函数。
首先创建class transformer。这个类有一个名为transform的方法。重写此方法,在此方法中,您可以使用ASM class reader和其他类来操纵构造函数的可见性。变换器完成后,您的客户端代码将可以访问构造函数。
您可以在此处详细了解:Changing a private Java constructor with ASM
嗯,这不是真正访问构造函数,但你仍然可以创建一个实例。我们假设您使用的是第三方库(让他们说是Guava)并且您可以访问代码,但是您不想更改由该代码加载的jar中的代码。 JVM由于某种原因(我知道,这不是很逼真,但是让我们假设代码在像Jetty这样的共享容器中,你不能改变共享代码,但你有单独的类加载上下文)然后您可以使用私有构造函数制作第三方代码的副本,将私有构造函数更改为代码中的protected或public,然后将您的类放在类路径的开头。从那时起,您的客户端可以使用修改后的构造函数并创建实例。
后一种变化称为link seam,它是一种接缝,其中使能点是类路径。
答案 7 :(得分:2)
您当然可以从同一个类及其内部类中的其他方法或构造函数访问私有构造函数。使用反射,您也可以在其他地方使用私有构造函数,前提是SecurityManager不会阻止您这样做。
答案 8 :(得分:2)
是的,我们可以访问私有构造函数或使用私有构造函数实例化一个类。 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
我希望你能得到它。
答案 9 :(得分:0)
是的,您可以使用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();
}
}
}
答案 10 :(得分:0)
拥有私有构造函数的基本前提是,拥有私有构造函数会限制除了自己的类代码之外的代码访问,从而无法创建该类的对象。
是的,我们可以在一个类中拥有私有构造函数,是的,可以通过创建一些静态方法使它们可访问,这些方法又为类创建新对象。
Class A{
private A(){
}
private static createObj(){
return new A();
}
Class B{
public static void main(String[]args){
A a=A.createObj();
}}
因此,要创建此类的对象,另一个类必须使用静态方法。
当我们将构造函数设为私有时,有一个静态方法有什么意义?
静态方法是这样的,以便在需要创建该类的实例时,可以在创建实例之前在静态方法中应用一些预定义的检查。例如,在Singleton类中,静态方法检查实例是否已经创建。如果实例已经创建,那么它只是简单地返回该实例而不是创建一个新实例。
public static MySingleTon getInstance(){
if(myObj == null){
myObj = new MySingleTon();
}
return myObj;
}
答案 11 :(得分:0)
我希望本示例可以为您提供帮助:
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();
}
}
}
输出: 被称为私有构造函数的
答案 12 :(得分:0)
我们不能在类之外访问私有构造函数,但是使用Java Reflection 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容器还会创建并注入具有私有构造函数的类的对象。
答案 13 :(得分: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();
}
}
}
答案 14 :(得分:0)
简单的答案是,我们可以在 Java 中使用私有构造函数。
在各种情况下,我们都可以使用私有构造函数。主要的是
答案 15 :(得分:0)
Reflection是Java中的API,我们可以使用它在运行时调用方法,而与它们使用的访问说明符无关。 要访问类的私有构造函数:
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();
}
}
在调用构造函数时会给出错误
java.lang.UnsupportedOperationException: It is a utility call
但是请记住使用反射API会导致开销问题
答案 16 :(得分:-1)
看看Singleton模式。它使用私有构造函数。
答案 17 :(得分:-2)
嗯,如果还有其他公共构造函数,你也可以。仅仅因为无参数构造函数是私有的并不意味着你不能实例化类。
答案 18 :(得分:-3)
您可以在课外访问它,非常容易访问 只是举一个singaltan类的例子我们都做同样的事情使私有构造函数和静态方法访问实例这里是与你的查询相关的代码
ClassWithPrivateConstructor.getObj().printsomething();
它肯定会起作用,因为我已经测试了