@@ -379,6 +379,84 @@ public class OutterClass
379379}
380380```
381381
382+ ** 为什么内部类可以使用外部类的private属性** :
383+
384+ 我们在InnerClass中增加一个方法,打印外部类的userName属性
385+
386+ ``` java
387+ // 省略其他属性
388+ public class OutterClass {
389+ private String userName;
390+ ......
391+ class InnerClass {
392+ ......
393+ public void printOut (){
394+ System . out. println(" Username from OutterClass:" + userName);
395+ }
396+ }
397+ }
398+
399+ // 此时,使用javap -p命令对OutterClass反编译结果:
400+ public classOutterClass {
401+ private String userName;
402+ ......
403+ static String access$000(OutterClass );
404+ }
405+ // 此时,InnerClass的反编译结果:
406+ class OutterClass $InnerClass {
407+ final OutterClass this $0 ;
408+ ......
409+ public void printOut ();
410+ }
411+
412+ ```
413+
414+ 实际上,在编译完成之后,inner实例内部会有指向outer实例的引用` this$0 ` ,但是简单的` outer.name ` 是无法访问private属性的。从反编译的结果可以看到,outer中会有一个桥方法` static String access$000(OutterClass) ` ,恰好返回String类型,即userName属性。正是通过这个方法实现内部类访问外部类私有属性。所以反编译后的` printOut() ` 方法大致如下:
415+
416+ ``` java
417+ public void printOut() {
418+ System . out. println(" Username from OutterClass:" + OutterClass . access$000(this . this $0 ));
419+ }
420+ ```
421+
422+ 补充:
423+
424+ 1 . 匿名内部类、局部内部类、静态内部类也是通过桥方法来获取private属性。
425+ 2 . 静态内部类没有` this$0 ` 的引用
426+ 3 . 匿名内部类、局部内部类通过复制使用局部变量,该变量初始化之后就不能被修改。以下是一个案例:
427+
428+ ``` java
429+ public class OutterClass {
430+ private String userName;
431+
432+ public void test (){
433+ // 这里i初始化为1后就不能再被修改
434+ int i= 1 ;
435+ class Inner {
436+ public void printName (){
437+ System . out. println(userName);
438+ System . out. println(i);
439+ }
440+ }
441+ }
442+ }
443+ ```
444+
445+ 反编译后:
446+
447+ ``` java
448+ // javap命令反编译Inner的结果
449+ // i被复制进内部类,且为final
450+ class OutterClass $1Inner {
451+ final int val$i;
452+ final OutterClass this $0 ;
453+ OutterClass$1Inner ();
454+ public void printName ();
455+ }
456+
457+ ```
458+
459+
382460### 条件编译
383461
384462—般情况下,程序中的每一行代码都要参加编译。但有时候出于对程序代码优化的考虑,希望只对其中一部分内容进行编译,此时就需要在程序中加上条件,让编译器只对满足条件的代码进行编译,将不满足条件的代码舍弃,这就是条件编译。
0 commit comments