代码:
class Outer {
private int xx = 123;
public Inner getInner() {
return new Inner();
}
public class Inner {
public int getDate() {
return xx;
}
}
}反编译Outer类,
C:\>javap -private Outer
Compiled from "Test.java"
class Outer extends java.lang.Object{
private int xx;
Outer();
public Outer$Inner getInner();
static int access$000(Outer);
}编译器自动生成了一个方法,access$000(),包访问权限,于是我在另外个类中访问 access$000() 方法,结果说
找不到这个方法,这又是为什么呢,编译器做的限制?一定就访问不了吗?另外用 Outer$Inner 访问内部类也不可以的,也是类似的限制吗?
class Outer {
private int xx = 123;
public Inner getInner() {
return new Inner();
}
public class Inner {
public int getDate() {
return xx;
}
}
}反编译Outer类,
C:\>javap -private Outer
Compiled from "Test.java"
class Outer extends java.lang.Object{
private int xx;
Outer();
public Outer$Inner getInner();
static int access$000(Outer);
}编译器自动生成了一个方法,access$000(),包访问权限,于是我在另外个类中访问 access$000() 方法,结果说
找不到这个方法,这又是为什么呢,编译器做的限制?一定就访问不了吗?另外用 Outer$Inner 访问内部类也不可以的,也是类似的限制吗?
解决方案 »
- 还是关于eclipse插件开发的一个入门问题,关于rcp程序在eclipse里的调试方法
- 再次求助linux下 crontab 运行java类的问题(困扰好几天了)
- 求对new 关键字的正确理解!!!!!!
- java的问题
- 菜鸟求助:请帮忙解决一下
- 文本中多个重复得<br><br>...<br>,如何用政则表达式替换为一个<br>??
- java正则提取数据
- getResourceAsStream()到底怎么用,请举一下实例。
- 用java做系统服务!高手请进!
- ■■100分请问:学习WEBSPHERE,J2EE有没有好的中文资料介绍,或者学习经验技巧等,谢谢■■
- 游戏背景随人物移动而移动的问题
- GUI编程学习第一弹:《计算器》。尽量面相对象,但依然不给力。仍旧全文注释,大家一起勉励
内部类和一般类的class文件还是有区别的,里面有标志位说明。
class Outer {
private int data = 9527;
public Inner getInner() {
return new Inner();
}
class Inner {
public int getDate() {
return data;
}
}
static int access$9527(Outer outer) { //手动编写的一个类似编译器自动生成的方法
System.out.println("success!");
return 1;
}
}反编译后为:
Compiled from "Test.java"
class Outer extends java.lang.Object{
private int data;
Outer();
public Outer$Inner getInner();
static int access$9527(Outer);
static int access$000(Outer);
}access$000()方法的字节码:
static int access$000(Outer);
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: getfield #1; //Field data:I
4: ireturn
LineNumberTable:
line 1: 0
然后在另一个类中访问这个方法,主要代码:
Outer o = new Outer();
int x = Outer.access$9527(o); 上面那样写是可以的,但是改成这样就不行了
int x = Outer.access$000(o);
结果提示:
Test2.java:5: 找不到符号
符号: 方法 access$000(Outer)
位置: 类 Outer
int x = Outer.access$000(o);
^
1 错误
从 access$000()方法生成的字节码,以及常量池中,没看到有什么问题,但是就
不能访问,我想是编译器做的手脚吧,但是不知道是在哪里做的手脚。另外access$000()需要传递一个Outer
类型的参数,但是从字节码来看,也没用到这个参数,不知道是干什么用的。
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: getfield #1; //Field data:I
4: ireturn
LineNumberTable:
line 1: 0 这里aload_0不就是用了Outer类型的参数吗
Outer outer = new Outer(); Class c = outer.getClass();
try {
Method method = c.getDeclaredMethod("access$000", new Class[]{Outer.class});
Object obj = method.invoke(outer, new Object[]{outer});
Integer i = (Integer) obj;
System.out.println(i);
} catch (Exception ex) {
}
}
}
以你的代码为例:内部类Inner中的方法
public int getDate() {
return xx;
}
生成的代码如下:(经javap 处理后)public int getDate();
LineNumberTable:
line 12: 0 Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: getfield #1; //Field this$0:LOuter;
4: invokestatic #3; //Method Outer.access$000:(LOuter;)I
7: ireturn看代码第4行:通过Outer.access$000(Outer o)来获取外部类对象o中的private型的数据成员(请注意:这可是从另外一个类中访问其它类的private型数据成员--不是通过反射技术)3)进一步:
若外部类定义了两个private 数据成员如下:
private int xx=12;
private float yy=12.4f;
这两个数据成员在内部类中都要访问,则编译器会自动生成两个access方法:
static int access$000(Outer); 用于内部类访问private int xx;
static float access$100(Outer); 用于内部类访问private float yy;4)这种内部类访问外部类中private数据成员的技术(不是通过反射!) 给安全留下了可能的小隐患(因为有些private数据成员是不提供外界访问它的所谓的getter()的).为此,编译器对自己自动生成的这些access$000()方法,在编译时进行检查,是不允许程序员直接来调用的.但是:我们可以利用JAVA编译器对类的编译特性来绕过这个检查:目的是,达到在自己的其它类中直接来调用这些access$000()方法.
这样,我们可采用这个技术(即:在自己的类中--注意不是内部类,而是外部类中直接来调用这个access$000(Outer);)来访问其它类的private的数据成员了.具体技术演示如下:
第一步:定义如下的类:
class Outer {
private final int xx = 123;
//由于是final,故不再自动生成access$000(Outer);public Inner getInner() {
return new Inner();
}
public class Inner {
public int getDate() {
return xx;
}
} //class Inner static int access$000(Outer)//这个是自已定义的!
{
return 1;
}
第二步:定义你的其它类,来直接调用这个access$000()方法
public class Test1
{
public static void main(String[] args)
{ System.out.println(Outer.access$000(new Outer())); //这个调用是没有问题的,因为是自己定义的!
}}将上述两个JAVA文件编译成class,成其是第二步的 Test1.class第三步:这是变戏法的一步:
将第一步的类Outer改为如下:
class Outer {
private int xx = 123;
//由于不是final,故自动生成access$000(Outer);public Inner getInner() {
return new Inner();
}
public class Inner {
public int getDate() {
return xx;
}
} //class Inner
/*将这个第一步中自己定义的access$000去掉,因为编译器会自动生成它!
static int access$000(Outer {
return 1;
} */重新编译第三步中的这个类,而第二步中的类Test.class不动它. 此时,我们达到了这样一个目的:在类Test1中调用了Outer类中编译器自动生成的这个access$000(...)了.