클래스의 개인 생성자에 어떻게 액세스 할 수 있습니까?
저는 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]);
인터뷰에서 개인 생성자에 대해 가장 먼저 묻는 질문은
클래스에 Private 생성자를 가질 수 있습니까?
그리고 때로는 후보자가 제공하는 대답은 아니오입니다. 개인 생성자를 가질 수 없습니다.
그래서 저는 말하고 싶습니다. 네, 클래스에 개인 생성자를 가질 수 있습니다.
특별한 일이 아닙니다. 이렇게 생각 해보세요.
비공개 : 비공개는 클래스 내에서만 액세스 할 수 있습니다.
생성자 : 클래스와 동일한 이름을 가지며 클래스의 객체가 생성 될 때 암시 적으로 호출되는 메서드.
또는 객체를 생성하려면 생성자를 호출해야한다고 말할 수 있습니다. 생성자가 호출되지 않으면 객체를 인스턴스화 할 수 없습니다.
즉, 클래스에 개인 생성자가 있으면 해당 객체는 클래스 내에서만 인스턴스화 될 수 있습니다. 간단히 말해서 생성자가 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.
}
}
이제 까다로운 부분, 왜 당신이 틀렸는 지 다른 답변에서 이미 설명했듯이 Reflection을 사용하여 제한을 우회 할 수 있습니다.
다음과 같이 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();
}
}
위의 답변이 마음에 들지만 개인 생성자가있는 클래스의 새 인스턴스를 만드는 두 가지 더 멋진 방법이 있습니다. 그것은 모두 당신이 성취하고자하는 것과 어떤 상황에서 무엇을 하느냐에 달려 있습니다.
1 : Java 계측 및 ASM 사용
이 경우 변압기로 JVM을 시작해야합니다. 이렇게하려면 새 Java 에이전트를 구현 한 다음이 변환기가 생성자를 변경하도록해야합니다.
먼저 변압기 클래스를 만듭니다 . 이 클래스에는 transform이라는 메서드가 있습니다. 이 메서드를 재정의하고이 메서드 내에서 ASM 클래스 판독기 및 기타 클래스를 사용하여 생성자의 가시성을 조작 할 수 있습니다 . 변환기가 완료되면 클라이언트 코드가 생성자에 액세스 할 수 있습니다.
이에 대한 자세한 내용은 여기에서 읽을 수 있습니다. ASM을 사용하여 개인용 Java 생성자 변경
2 : 생성자 코드 다시 작성
글쎄, 이것은 실제로 생성자에 액세스하는 것이 아니지만 여전히 인스턴스를 만들 수 있습니다. 타사 라이브러리 (구아바라고 가정 해 보겠습니다)를 사용하고 코드에 액세스 할 수 있지만 어떤 이유로 JVM에 의해로드되는 jar에서 해당 코드를 변경하고 싶지 않다고 가정 해 보겠습니다. 실물 같지는 않지만 코드가 Jetty와 같은 공유 컨테이너에 있고 공유 코드를 변경할 수 없지만 별도의 클래스 로딩 컨텍스트가 있다고 가정 해 봅시다. 그러면 개인 생성자를 사용하여 타사 코드의 복사본을 만들 수 있습니다. private 생성자를 코드에서 protected 또는 public으로 설정 한 다음 클래스 경로의 시작 부분에 클래스를 넣으십시오. 이 시점에서 클라이언트는 수정 된 생성자를 사용하고 인스턴스를 만들 수 있습니다.
이 후자의 변경을 링크 이음 이라고하며 활성화 지점이 클래스 경로 인 일종의 이음새입니다.
물론 동일한 클래스 및 내부 클래스의 다른 메서드 또는 생성자에서 개인 생성자에 액세스 할 수 있습니다. 리플렉션을 사용하면 SecurityManager가 그렇게하는 것을 방해하지 않는 한 개인 생성자를 다른 곳에서도 사용할 수 있습니다.
예, @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();
}
}
예, 개인 생성자에 액세스하거나 개인 생성자로 클래스를 인스턴스화 할 수 있습니다. 자바 리플렉션 API와 싱글 톤 디자인 패턴은 개인 생성자에 접근하기 위해 개념을 많이 활용했습니다. 또한 Spring 프레임 워크 컨테이너는 Bean의 private 생성자에 액세스 할 수 있으며이 프레임 워크는 Java Reflection 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
나는 당신이 그것을 얻길 바랍니다.
이 예제가 도움이되기를 바랍니다.
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();
}
}
}
출력 : 개인 생성자가 호출 됨
싱글 톤 패턴을보세요. 개인 생성자를 사용합니다.
예,를 사용하여 개인 생성자로 인스턴스를 인스턴스화 할 수 있습니다. 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();
}
}
}
개인 생성자를 갖는 기본 전제는 개인 생성자가 자신의 클래스 코드 이외의 코드에 대한 액세스가 해당 클래스의 객체를 만드는 것을 제한한다는 것입니다.
예, 우리는 클래스에 개인 생성자를 가질 수 있으며 예, 클래스에 대한 새 객체를 생성하는 일부 정적 메서드를 만들어 액세스 할 수 있습니다.
Class A{
private A(){
}
private static createObj(){
return new A();
}
Class B{
public static void main(String[]args){
A a=A.createObj();
}}
따라서이 클래스의 객체를 만들려면 다른 클래스가 정적 메서드를 사용해야합니다.
생성자를 비공개로 만들 때 정적 메서드를 사용하는 이유는 무엇입니까?
Static methods are there so that in case there is a need to make the instance of that class then there can be some predefined checks that can be applied in the static methods before creation of the instance. For example in a Singleton class, the static method checks if the instance has already been created or not. If the instance is already created then it just simply returns that instance rather than creating a new one.
public static MySingleTon getInstance(){
if(myObj == null){
myObj = new MySingleTon();
}
return myObj;
}
We can not access private constructor outside the class but using Java Reflection API we can access private constructor. Please find below code:
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));
}
}
}
}
If you are using Spring IoC, Spring container also creates and injects object of the class having private constructor.
I tried like this it is working. Give me some suggestion if i am wrong.
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();
}
}
}
Simple answer is yes we can have private constructors in Java.
There are various scenarios where we can use private constructors. The major ones are
- Internal Constructor chaining
- Singleton class design pattern
Reflection is an API in java which we can use to invoke methods at runtime irrespective of access specifier used with them. To access a private constructor of a class:
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();
}
}
When calling the constructor it will give the error java.lang.UnsupportedOperationException: It is a utility call
But remember using reflection api cause overhead issues
Well, you can also if there are any other public constructors. Just because the parameterless constructor is private doesn't mean you just can't instantiate the class.
you can access it outside of the class its very easy to access just take an example of singaltan class we all does the same thing make the private constructor and access the instance by static method here is the code associated to your query
ClassWithPrivateConstructor.getObj().printsomething();
it will definately work because i have already tested
참고URL : https://stackoverflow.com/questions/2599440/how-can-i-access-a-private-constructor-of-a-class
'Program Club' 카테고리의 다른 글
| Reporting Services에서 단일 매개 변수에 대한 여러 값 전달 (0) | 2020.11.09 |
|---|---|
| 2008 년에 Dojo는 어떻게 되었습니까? (0) | 2020.11.09 |
| winforms 텍스트 상자에 검은 색 점 (•)이 표시되는 passwordchar는 무엇입니까? (0) | 2020.11.09 |
| Spring / Java 오류 : 네임 스페이스 요소 'annotation-config'… JDK 1.5 이상 (0) | 2020.11.09 |
| "do {…} while ()"루프가 필요합니까? (0) | 2020.11.09 |