阅读到thining in java第八章《接口与内部类》的时候,在研究一个例子程序的时候遇到了一个小问题,请大家帮忙解答一下。
该例子程序涉及到了三个class文件,分别是Contents.java,Destination.java,Parcel10.java。其中的Contents.java和Destination.java是两个interface,而Parcel10.java是含有静态内部类的一个类文件。具体代码如下:
Contents.javapublic interface Contents {
int value();
}
Destination.javapublic interface Destination {
String readLabel();
}
Parcel10.javapublic class Parcel10 {
private static class PContents implements Contents {
private int i = 11;
public int value() {
return i;
}
}
protected static class PDestination implements Destination {
private String label;
private PDestination(String whereTo) {
label = whereTo;
}
public String readLabel() {
return label;
}
public static void f() {}
static int x = 10;
static class AnotherLevel {
public static void f() {}
static int x = 10;
}
}
public static Destination dest(String s) {
return new PDestination(s);
}
public static Contents cont() {
return new PContents();
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Contents c = cont();
Destination d = dest("Tanzania");
}
}
编译Parcel10.java得到了如下的class文件:Contents.class
Destination.class
Parcel10$1.class
Parcel10$PContents.class
Parcel10$PDestination$AnotherLevel.class
Parcel10$PDestination.class
Parcel10.class
我的疑惑就是:编译出来的大部分class文件我都能理解,但是关于这个Parcel10$1.class文件我不知道是如何产生的,我能理解Parcel10$1.class是一个Parcel10的匿名内部类,但是我的代码中并没有创建一个匿名类,不知道这个Parcel10$1.class是如何产生的,请赐教。
该例子程序涉及到了三个class文件,分别是Contents.java,Destination.java,Parcel10.java。其中的Contents.java和Destination.java是两个interface,而Parcel10.java是含有静态内部类的一个类文件。具体代码如下:
Contents.javapublic interface Contents {
int value();
}
Destination.javapublic interface Destination {
String readLabel();
}
Parcel10.javapublic class Parcel10 {
private static class PContents implements Contents {
private int i = 11;
public int value() {
return i;
}
}
protected static class PDestination implements Destination {
private String label;
private PDestination(String whereTo) {
label = whereTo;
}
public String readLabel() {
return label;
}
public static void f() {}
static int x = 10;
static class AnotherLevel {
public static void f() {}
static int x = 10;
}
}
public static Destination dest(String s) {
return new PDestination(s);
}
public static Contents cont() {
return new PContents();
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Contents c = cont();
Destination d = dest("Tanzania");
}
}
编译Parcel10.java得到了如下的class文件:Contents.class
Destination.class
Parcel10$1.class
Parcel10$PContents.class
Parcel10$PDestination$AnotherLevel.class
Parcel10$PDestination.class
Parcel10.class
我的疑惑就是:编译出来的大部分class文件我都能理解,但是关于这个Parcel10$1.class文件我不知道是如何产生的,我能理解Parcel10$1.class是一个Parcel10的匿名内部类,但是我的代码中并没有创建一个匿名类,不知道这个Parcel10$1.class是如何产生的,请赐教。
jdk6
myeclipse6.5
你再试试吧
反编译一下看看
同时,我反编译这个class文件,内容却是如下:
static class Parcel10$1
{
}
期待楼下高手解答
我机器没反编译工具,我的环境是jdk1.5,我自己javadoc编译的,没使用IDE工具。
return new PDestination(s);
}
public static Contents cont() {
return new PContents();
}把这两个方法注释掉就没有了,继续研究.......
你的解释我没太看明白,我直行了一下javap -c Parcel10.class,打印出来的东西看得不是很明白,没找到那个假的构造函数。另外按#8的方法我测试了一下,去掉 public static Destination dest(String s) {
return new PDestination(s);
}
public static Contents cont() {
return new PContents();
}这两个函数之后,再从新编译确实就没有了Parcel10$1.class这个文件,貌似按你的说法无法解释这个现象。
回你和13#:去掉这两个方法的确是没有了,理由在于
new PContents();和new PDestination(s);你可以试着把这两个方法去掉,加上下面两个成员变量:PContents pContents = new PContents();
PDestination pDestination = new PDestination(s);又会有了。必须要去访问构造函数,编译器才会去生成那个虚拟类的。怎么看javap的问题。我现在在公司的笔记本上,没装Java的环境,晚上回去后帖出来,分析给你看吧。但是不是javap -c Parcel10而是,javap -c Parcel10$PDestination
我记得这问题是有好几次都被误提为java:compiler的一个bug,但都被invalid掉了。
int value();
}package com.lxxzhy.test;public class CommonTesting {
private Contents c = new PContents(); protected static class PContents implements Contents {
private int i = 11;
public int value() {
return i;
}
}
}
那个XXXXX$1.class的文件就没有了.
String readLabel();}package com.lxxzhy.test;public class CommonTesting { private Destination d = new PDestination(""); protected static class PDestination implements Destination {
private String label; private PDestination(String whereTo) {
label = whereTo;
} public String readLabel() {
return label;
} public static void f() {
} static int x = 10; static class AnotherLevel {
public static void f() {
} static int x = 10;
}
}
}那个XXXX$1.class的文件又出现了,由此可以证明,并非什么有没有调用构造函数的问题,而可能在于,静态内部类中又有静态内部类的问题(猜想,待证).
int value();
}package com.lxxzhy.test;public class CommonTesting { private Contents c = new PContents(""); protected static class PContents implements Contents {
private int i = 11; private PContents(String whereTo) {
} public int value() {
return i;
}
}
}就是对静态内部类定义了构造方法,这时编译,那个XXXXXX$1.class再次出现,看来我#21的推断是不正确的.对比#20和这里的代码,可以看出:没有自定义静态内部类的构造方法,那个神气的类文件不会出现,定义了,就神奇般出现了.
Compiled from "Parcel10.java"
public class Parcel10$PDestination extends java.lang.Object implements Destinati
on{
static int x;public java.lang.String readLabel();
Code:
0: aload_0
1: getfield #3; //Field label:Ljava/lang/String;
4: areturnpublic static void f();
Code:
0: returnParcel10$PDestination(java.lang.String, Parcel10$1);
Code:
0: aload_0
1: aload_1
2: invokespecial #1; //Method "<init>":(Ljava/lang/String;)V
5: returnstatic {};
Code:
0: bipush 10
2: putstatic #4; //Field x:I
5: return}
D:\workspace\Test\src>javap -c Parcel10$PContents
Compiled from "Parcel10.java"
class Parcel10$PContents extends java.lang.Object implements Contents{
public int value();
Code:
0: aload_0
1: getfield #3; //Field i:I
4: ireturnParcel10$PContents(Parcel10$1);
Code:
0: aload_0
1: invokespecial #1; //Method "<init>":()V
4: return}请注意这两句:Parcel10$PDestination(java.lang.String, Parcel10$1);和Parcel10$PContents(Parcel10$1);对比下12#我给出的Eclipse的结果和说的话。后来你做的实验,请也用这个方法看看到底。
D:\workspace\Test\src>javap -c Parcel10
Compiled from "Parcel10.java"
public class Parcel10 extends java.lang.Object{
public Parcel10();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: returnpublic static Destination dest(java.lang.String);
Code:
0: new #2; //class Parcel10$PDestination
3: dup
4: aload_0
5: aconst_null
6: invokespecial #3; //Method Parcel10$PDestination."<init>":(Ljava/lang/
String;LParcel10$1;)V
9: areturnpublic static Contents cont();
Code:
0: new #4; //class Parcel10$PContents
3: dup
4: aconst_null
5: invokespecial #5; //Method Parcel10$PContents."<init>":(LParcel10$1;)V 8: areturnpublic static void main(java.lang.String[]);
Code:
0: invokestatic #6; //Method cont:()LContents;
3: astore_1
4: ldc #7; //String Tanzania
6: invokestatic #8; //Method dest:(Ljava/lang/String;)LDestination;
9: astore_2
10: return}
注意这两句,6: invokespecial #3; //Method Parcel10$PDestination."<init>":(Ljava/lang/
String;LParcel10$1;)V和5: invokespecial #5; //Method Parcel10$PContents."<init>":(LParcel10$1;)V如果编译器不构造Parcel10$1就会报没有类对吧?所以必须构造一个空的。为什么需要修改默认的构造函数,参造我11#说的。如果你不信,去翻翻Java编译器的bug报告,我记得有这么一条的。Okay?不要乱猜了~20#说的,自己用这个求证下,说不定什么原因没生成,但不要去追究了。知道是这样一回事就可以了
请看我第一个回复,11#。那个特殊的构造参数是为了让你的内部类的构造函数私有化。你20#的例子,没必要改成22#那样,你改成这样,也可以出现了:public class CommonTesting { private Contents c = new PContents(); protected static class PContents implements Contents {
private int i = 11;
private PContents() {
} public int value() {
return i;
}
}
}你22#改成这样,就不出现了:public class CommonTesting { private Contents c = new PContents(""); protected static class PContents implements Contents {
private int i = 11; public PContents(String whereTo) {
} public int value() {
return i;
}
}
}
这次彻底明白了吧?
======================
去掉这两个方法的确是没有了,理由在于new PContents();和new PDestination(s);你可以试着把这两个方法去掉,加上下面两个成员变量:PContents pContents = new PContents();
PDestination pDestination = new PDestination(s);又会有了。必须要去访问构造函数,编译器才会去生成那个虚拟类的.
========================
所以我试试是否有new new PContents();或者new PDestination(s);就必然出现$1.class.结果不是这样的.现在看来,即使定义了静态内部类的构造方法,如果用非private修饰的,也不会出现.
static PContents pContents = new PContents(); private static class PContents implements Contents {
private int i = 11;
public int value() {
return i;
}
}
// protected static class PDestination implements Destination {
// private String label;
// private PDestination(String whereTo) {
// label = whereTo;
// }
// public String readLabel() {
// return label;
// }
// public static void f() {}
// static int x = 10;
// static class AnotherLevel {
// public static void f() {}
// static int x = 10;
// }
// }
/**
* @param args
*/
public static void main(String[] args) {
Contents c = Parcel10.pContents;
}
}也会有Parcel10$1.class~这又是另外一个问题了:私有化的内部类的构造函数问题~:p