简介
Java编译器在编译过程中自动生成accessxxx方法
实例
接下来,我们就看看那些情况会生成accessxxx方法有啥特点
情况一
私有内部类访问外部类私有成员变量,源代码如下
public class OutClass extends Base {
private String test = "test";
String test2 = "test";
private String test3 = "test";
private class InnerClass {
private InnerClass() {
}
public void innerTest() {
String test = OutClass.this.test;
String test2 = OutClass.this.test2;
String test3 = OutClass.this.test3;
String baseTest = OutClass.this.baseTest;
outTest();
outTest2();
outTest3();
baseTest();
}
}
private void outTest() {
}
void outTest2() {
}
public void outTest3() {
}
}
首先看一下编译后外部类字节码,通过javap -c查看
public class OutClass extends Base {
java.lang.String test2;
public sort.OutClass();
Code:
0: aload_0
1: invokespecial #4 // Method sort/Base."<init>":()V
4: aload_0
5: ldc #5 // String test
7: putfield #3 // Field test:Ljava/lang/String;
10: aload_0
11: ldc #5 // String test
13: putfield #6 // Field test2:Ljava/lang/String;
16: aload_0
17: ldc #5 // String test
19: putfield #2 // Field test3:Ljava/lang/String;
22: return
void outTest2();
Code:
0: return
public void outTest3();
Code:
0: return
static java.lang.String access$000(sort.OutClass);
flags: ACC_STATIC, ACC_SYNTHETIC
Code:
0: aload_0
1: getfield #3 // Field test:Ljava/lang/String;
4: areturn
static java.lang.String access$100(sort.OutClass);
flags: ACC_STATIC, ACC_SYNTHETIC
Code:
0: aload_0
1: getfield #2 // Field test3:Ljava/lang/String;
4: areturn
static void access$200(sort.OutClass);
flags: ACC_STATIC, ACC_SYNTHETIC
Code:
0: aload_0
1: invokespecial #1 // Method outTest:()V
4: return
}
看到外部类的中多了access100方法以及没有内部类,而在目录中会多一个OutClassInnerClass.class
class OutClass$InnerClass {
private OutClass$InnerClass(OutClass var1) {
this.this$0 = var1;
}
public void innerTest() {
String test = OutClass.access$000(this.this$0);
String test2 = this.this$0.test2;
String test3 = OutClass.access$100(this.this$0);
String baseTest = this.this$0.baseTest;
OutClass.access$200(this.this$0);
this.this$0.outTest2();
this.this$0.outTest3();
this.this$0.baseTest();
}
}
类的访问权限会被由private修改成default,test方法中调用外部类的私有成员变成对了OutClass.access0)方法的调用
情况二
外部类调用内部类私有成员
public class sort.OutClass {
public sort.OutClass();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void outTest();
Code:
0: new #2 // class sort/OutClass$InnerClass
3: dup
4: aload_0
5: aconst_null
6: invokespecial #3 // Method sort/OutClass$InnerClass."<init>":(Lsort/OutClass;Lsort/OutClass$1;)V
9: astore_1
10: aload_1
11: invokestatic #4 // Method sort/OutClass$InnerClass.access$100:(Lsort/OutClass$InnerClass;)Ljava/lang/String;
14: astore_2
15: aload_1
16: getfield #5 // Field sort/OutClass$InnerClass.test2:Ljava/lang/String;
19: astore_3
20: aload_1
21: invokestatic #6 // Method sort/OutClass$InnerClass.access$200:(Lsort/OutClass$InnerClass;)Ljava/lang/String;
24: astore 4
26: aload_1
27: getfield #7 // Field sort/OutClass$InnerClass.baseTest:Ljava/lang/String;
30: astore 5
32: aload_1
33: invokevirtual #8 // Method sort/OutClass$InnerClass.innerTest:()V
36: aload_1
37: invokestatic #9 // Method sort/OutClass$InnerClass.access$300:(Lsort/OutClass$InnerClass;)V
40: aload_1
41: invokevirtual #10 // Method sort/OutClass$InnerClass.innerTest3:()V
44: aload_1
45: invokevirtual #11 // Method sort/OutClass$InnerClass.baseTest:()V
48: return
}
外部类调用内部类私有成员内部类也会生成access$xxx方法
总结
accessxxx方法flag是ACC_STATIC、 ACC_SYNTHETIC,ACC_STATIC是指静态方法,ACC_SYNTHETIC是指此方法是编译器生成的。调用asscess方法要比直接使用变量消耗性能,大量的access方法会对性能有一些影响。另外,在Android中art以及dalvik虚拟机执行的是dex文件,dex中方法数不能超过64K,编译器多生成的access方法,意味着可能要多分几个dex包,意味着会增加包的体积,同样也会增加虚拟机加载dex时间,造成冷启动启动时间延长。<P>
如何减少access方法生成呢?主要有两个方案。
- 方案一:开发者开发时把访问权限改成default,这个显然有点难度
- 方案二:通过asm查找并删除flags标记为ACC_STATIC、 ACC_SYNTHETIC,前缀为access的方法
网友评论