Skip to content

Commit 1dd05db

Browse files
authored
Update syntactic-sugar.md
增加内部类的知识点
1 parent 8cd0f88 commit 1dd05db

File tree

1 file changed

+78
-0
lines changed

1 file changed

+78
-0
lines changed

docs/java/basis/syntactic-sugar.md

+78
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)