gpt4 book ai didi

java - 为什么拥有静态嵌套类会导致在不在源代码中时添加第二个构造函数?

转载 作者:搜寻专家 更新时间:2023-11-01 02:24:43 24 4
gpt4 key购买 nike

我试图使用反射打破 BillPaugh Singleton 解决方案,我能够做到,但在访问 BillPaughSingleTon 解决方案时我可以看到两个构造函数。为什么这样 ?同样通过反复试验发现 HelperClass 内部的行导致了这一点。又是为什么?

BillPaugh类

package creational.BillPaugh;

public class SingleTonBillPaugh
{
private SingleTonBillPaugh instance;

public static SingleTonBillPaugh getInstance()
{
return SingleTonHelper.instance;
}

private SingleTonBillPaugh()
{
System.out.println(Thread.currentThread().getName() + " instance is going to be created");
}

static class SingleTonHelper
{
private static final SingleTonBillPaugh instance = new SingleTonBillPaugh(); //if we remove this line, multiple constructor will not be there. But this line is needed for singleton.
}
}

使用反射打破 SingleTon。

package creational.BillPaugh;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

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

SingleTonBillPaugh singletonInstance1 = SingleTonBillPaugh.getInstance();
System.out.println("singletonInstance1 " + singletonInstance1);

SingleTonBillPaugh singletonInstance2;
Constructor[] constructors = SingleTonBillPaugh.class.getDeclaredConstructors();

for (Constructor construct : constructors)
{
construct.setAccessible(true);
try
{
singletonInstance2 = (SingleTonBillPaugh) construct.newInstance();
System.out.println("singletonInstance2 " + singletonInstance2);
}
catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException e)
{
e.printStackTrace();
}
}// end for

Constructor[] constructors2 = NormalClass.class.getDeclaredConstructors();

}
}

两个构造函数的证明。

enter image description here

最佳答案

这是我的看法:

由于源码中的SingleTonBillPaugh构造函数是privateSingleTonBillPaugh$SingleTonHelper无法访问,所以编译器生成了一个合成构造函数SingleTonBillPaugh$SingleTonHelper 可以 访问。这就是合成方法和构造函数的用途:提供一种访问包含类的私有(private)数据的方法。

在我看来更大的问题是为什么合成构造函数接受一个参数,为什么参数的类型是 SingleTonBillPaugh$1? (你的截图让它看起来像是一个 SingleTonBillPaugh 实例,但在我的测试中它实际上是一个 SingleTonBillPaugh$1 实例——也就是说,除了SingleTonBillPaughSingleTonBillPaugh$SingleTonHelper)。

我对那个问题的回答是:因为否则,将有两个构造函数的区别仅在于一个是合成的并且可由 SingleTonBillPaugh$SingleTonHelper 访问,另一个不是。 Java 要求签名比这更加不同,因此它生成一个类的唯一原因是将合成构造函数与非合成构造函数区分开来。

我们可以看到我们确实有一个 SingleTonBillPaugh$1 类,如果我们 javap -p -c SingleTonBillPaugh\$1 它,我们得到:

class SingleTonBillPaugh$1 {
}

没有比这更小的了,这表明它确实纯粹充当合成构造函数的参数类型。通过使用 javap -p -c SingleTonBillPaugh\$SingleTonHelper 查看 SingleTonBillPaugh$SingleTonHelper 的字节码,我们可以进一步确认:

class SingleTonBillPaugh$SingleTonHelper {
private static final SingleTonBillPaugh instance;

SingleTonBillPaugh$SingleTonHelper();
Code:
0: aload_0
1: invokespecial #2 // Method java/lang/Object."<init>":()V
4: return

static SingleTonBillPaugh access$000();
Code:
0: getstatic #1 // Field instance:LSingleTonBillPaugh;
3: areturn

static {};
Code:
0: new #3 // class SingleTonBillPaugh
3: dup
4: aconst_null
5: invokespecial #4 // Method SingleTonBillPaugh."<init>":(LSingleTonBillPaugh$1;)V
8: putstatic #1 // Field instance:LSingleTonBillPaugh;
11: return
}

注意它是如何(就在最后)调用构造函数的单参数版本(传入 null)。

事实上,它似乎总是这样做——将一个新参数添加到构造函数参数列表的末尾。如果我更改私有(private)构造函数以接受 String 并更新 SingleTonHelper 以将其传递给 "",则合成构造函数最终变为 SingleTonBillPaugh (字符串,SingleTonBillPaugh$1)


在下面回答你的问题:

I kept one sysout in no argument constructor and when inner class called no argument constructor of outer class (which supposedly be synthetic constructor) the same sysout is printed. Why so? is it because internally synthetic constructor calls my provided pvt constructor?

没错,合成构造函数调用私有(private)构造函数。像这样的时候,很高兴深入了解字节码:

这是我的 SingleTonBillPaugh.java 副本:

public class SingleTonBillPaugh
{
public static SingleTonBillPaugh getInstance()
{
return SingleTonHelper.instance;
}

private SingleTonBillPaugh()
{
System.out.println(Thread.currentThread().getName() + " instance is going to be created");
}

static class SingleTonHelper
{
private static final SingleTonBillPaugh instance = new SingleTonBillPaugh();
}
}

如果我们编译它,然后使用 javap -p -c SingleTonBillPaugh,我们得到:

public class SingleTonBillPaugh {
public static SingleTonBillPaugh getInstance();
Code:
0: invokestatic #2 // Method SingleTonBillPaugh$SingleTonHelper.access$000:()LSingleTonBillPaugh;
3: areturn

private SingleTonBillPaugh();
Code:
0: aload_0
1: invokespecial #3 // Method java/lang/Object."<init>":()V
4: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
7: new #5 // class java/lang/StringBuilder
10: dup
11: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V
14: invokestatic #7 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
17: invokevirtual #8 // Method java/lang/Thread.getName:()Ljava/lang/String;
20: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
23: ldc #10 // String instance is going to be created
25: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: invokevirtual #11 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
31: invokevirtual #12 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
34: return

SingleTonBillPaugh(SingleTonBillPaugh$1);
Code:
0: aload_0
1: invokespecial #1 // Method "<init>":()V
4: return
}

正如我们所见,以源代码形式编写的 SingleTonBillPaugh(SingleTonBillPaugh$1) 构造函数基本上是:

SingleTonBillPaugh(SingleTonBillPaugh$1 unused) {
this();
}

关于java - 为什么拥有静态嵌套类会导致在不在源代码中时添加第二个构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27815030/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com