不通过反射在其它类中直接调用access$000方法,即:如何绕过这个检查
2016-03-09 08:57
417 查看
1)static Type access$iii(Outer);
是JAVA编译器自动生成的十分重要的方法(该方法的个数由你的内部类要访问的外部类的变量个数相关),目的是:用于内部类访问外部类的数据成员时使用.
2)因此:JAVA编译器在生成内部类的访问外部类的数据成员时,会自动生成代码来调用这个方法.
以你的代码为例:内部类Inner中的方法
public int getDate() {
return xx;
}
生成的代码如下:(经javap 处理后)
看代码第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的数据成员了.
具体技术演示如下:
第一步:定义如下的类:
将上述两个JAVA文件编译成class,成其是第二步的 Test1.class
第三步:这是变戏法的一步:
将第一步的类Outer改为如下:
此时,我们达到了这样一个目的:在类Test1中调用了Outer类中编译器自动生成的这个access$000(...)了.
是JAVA编译器自动生成的十分重要的方法(该方法的个数由你的内部类要访问的外部类的变量个数相关),目的是:用于内部类访问外部类的数据成员时使用.
2)因此:JAVA编译器在生成内部类的访问外部类的数据成员时,会自动生成代码来调用这个方法.
以你的代码为例:内部类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(...)了.
相关文章推荐
- HUST 1599 - Multiple(动态规划)
- 日经春秋 20160309
- HUST 1599 - Multiple(动态规划)
- C#进行Visio二次开发之文件导出及另存Web页面
- 初学HTML5、初入前端
- C#用正则表达式 获取网页源代码标签的属性或值
- 浅谈Java的虚拟机结构以及虚拟机内存的优化
- vitrual与类的大小
- 日志记录—Java中的日志——Java.util.logging、log4j、commons-logging
- 天声人語 20160309 女性が働きやすい社会へ
- phpmyadmin误删表后的恢复过程
- javascript html5移动端轻松实现文件上传
- javascript事件绑定学习要点
- 守护线程
- Java反射机制的学习
- WebPack系列教程(二):动机
- 欧拉项目第二题 Even Fibonacci numbers
- hadoop 数据类型
- 有糖培训任务1-12课答案
- Maven资源库pom文件引入依赖jar包的