2010-04-08 127 views
40

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

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

我回答'不',但是错了。

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

+11

对于Java中,最相似的面试问题都可以回答“是的,你可以做几乎任何东西,但如果你?!一般来说,没有!”就我个人而言,我认为这是一个愚蠢的问题。我不希望我的开发人员这样做,所以我不在乎他们是否知道它。更实用的语言细节应该重要_far_更多。知道反射的更普遍的用途可能就足够了。了解OO设计模式和语言陷阱比_far_更重要,比晦涩,应该避免的语言结构更重要。 – nicerobot 2010-04-08 12:30:56

+0

@nicerobot,我对你有些不满,有些时候这种技巧打败了目的的实际含义 – gmhk 2010-04-08 18:26:29

+0

允许使用反射类来访问私有构造函数是否是一个好习惯? – gmhk 2010-06-18 08:42:19

回答

50
  • 您可以在类内部访问(例如,在一个公共静态工厂方法)
  • 如果它是一个嵌套类,可以从封装类
  • 符合相应的权限,您可以访问它访问它与反射

这是不是很清楚,如果任何这些适用 - 虽然你可以提供更多的信息?

+0

我用你提到的第二种方法(虽然没有打算:)),但似乎它不工作在C#中。我对吗? – 2016-08-14 16:12:31

+0

@alireza:是的,C#有不同的规则。 – 2016-08-15 03:59:22

+0

'如果它是一个嵌套类,你可以从封闭类访问它'任何示例? – 2016-09-06 09:54:43

15

这可以使用反射来实现。

考虑一类测试,具有私有构造函数:

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]); 
+0

更正了“反身性” - >“反思”。 – sleske 2010-04-08 11:39:57

+1

是的,我检查,它的工作原理,感谢 – gmhk 2010-04-08 18:26:51

1

你当然也可以访问来自同一类的其他方法或构造函数和它的内部类的私有构造。使用反射,您也可以在别处使用私有构造函数,前提是SecurityManager不会阻止您这样做。绕过限制

55

一种方法是使用感言:

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!"; 
    } 
} 
+0

,为什么我们需要在这里的最后一个方法,重写toString? – annabretsko 2017-11-04 13:18:55

+0

@maryanne它只是为了让结果在输出中更加明显。这不是必需的。 – 2017-11-04 13:22:28

+0

'新的类[0]'和'新的对象[0]'是不必要的。 – shmosel 2018-02-22 21:30:54

1

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

+1

Singleton使用私有构造函数,在类之外我们不会实例化,但我们使用已经实例化的类 – gmhk 2010-04-08 12:00:44

0

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

5

是关于面试私有构造问的,

我们能在一个类中私有构造函数的第一个问题?

有时,候选人给出的答案是,不,我们不能有私人构造函数。

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

这是没有特别的事情,再想想这种方式,

私人:任何私人只能从类中进行访问。

构造函数:一个与类的名称相同的方法,当类的对象被创建时,它被隐式地调用。

,或者你可以说,去创造你需要调用它的构造方法的对象,如果构造不叫那么对象不能被实例化。

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

有什么好处 这个概念可以实现以达到singleton对象(这意味着可以只创建一个类的对象)。

请看下面的代码,

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. 

    } 
} 
+0

为什么有人会在面试中问这样一个挑剔的,语言特定的问题? – dfeuer 2014-06-25 05:14:32

+1

@dfeuer嗯,我想当你要参加Java Developer的面试时,他们可能会问你特定于语言(Java atleast *)的问题。 – gprathour 2014-06-25 06:18:16

3

是的,你可以,正如@乔恩街仅提及。

访问私有构造的另一种方式是通过创建这个类中的公共静态方法和具有它的返回类型为对象。

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

我遇到了同样的问题,并找到@Jon Steet提到的各种解决方案。在Java中还通过使用工厂方法遇到了类似“Reflection”的新事物。 但最后他们期待的简单实现很简单,因为这! 希望这有助于家伙:) – Tapeshvar 2014-06-25 05:02:46

+0

如果这是一个被接受的答案,那么这个问题是误导。这不会访问定义它的类之外的构造函数,它只会访问由私有构造函数构造的对象。 – Ray 2016-06-09 13:13:16

-1

你可以在类的外部访问它它很容易访问 只取singaltan类的例子大家都做同样的事情使私有构造和访问由这里的静态方法的实例相关的代码您查询

ClassWithPrivateConstructor.getObj().printsomething(); 

它一定会工作,因为我已经测试

+0

那不访问构造函数,只访问构造的对象。 – Ray 2016-06-09 13:10:31

3

使用Java反射机制如下:

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

首先将setAccessible设置为true,然后调用newInstance()。 c.setAccessible(true); c.newInstance(); – mahesh 2016-10-01 12:26:34

1

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

1:那么在这种情况下,你必须用变压器启动JVM使用Java instrumentationASM

。要做到这一点,你必须实现一个新的Java代理,然后让这个变换器为你改变构造函数。

首先创建class transformer。这个类有一个叫做transform的方法。重写此方法并在此方法内部,您可以使用ASM class reader和其他类来操纵构造函数的可见性。转换完成后,您的客户端代码将可以访问构造函数。

你可以阅读更多关于此这里:Changing a private Java constructor with ASM

2:重写构造函数代码

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

这后一个变化被称为link seam,这是一种接缝,其中启用点是类路径。

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

是的,我们可以访问私有构造函数或用私有构造函数实例化一个类。 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[] = class.getDeclaredConstructor(); 
      con[0].setAccessible(true); 
      con[0].newInstance(null); 
     }catch(Exception e){} 

    } 
} 

output: 
private constructor invocation 

我希望你明白了。

0

要访问该类的私有构造函数,Java会提供反射。你可以在java.lang.Classjava.lang.refelect.Constructor的帮助下完成。

使用getDeclaredConstructor()方法java.lang.Class。它将重构构造函数对象数组

package org.websparrow.access; 

public class Honda { 

// private constructor 
private Honda(){ 
    System.out.println("I am private constructor of Honda class."); 
    } 
} 

实例化Car类本田类。

package org.websparrow.access; 

import java.lang.reflect.Constructor; 

public class Car { 
public static void main(String[] args) { 
    try { 

     Class<?> cls = Class.forName("org.websparrow.access.Honda"); 

     Constructor<?>[] cons = cls.getDeclaredConstructors(); 
     cons[0].setAccessible(true); 
     cons[0].newInstance(); 

    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 
} 

欲了解更多详情可采取全球化志愿服务青年的形式How to access private fields, methods and constructors of a class in Java

相关问题