@@ -246,7 +246,7 @@ public static transient void print(String strs[])
246
246
}
247
247
```
248
248
249
- 从反编译后代码可以看出,可变参数在被使用的时候,他首先会创建一个数组,数组的长度就是调用该方法是传递的实参的个数,然后再把参数值全部放到这个数组当中,然后再把这个数组作为参数传递到被调用的方法中。(注:` trasient ` 仅在修饰成员变量时有意义,此处 “修饰方法” 是由于在 javassist 中使用相同数值分别表示 ` trasient ` 以及 ` vararg ` ,见 [ 此处] ( https://github.com/jboss-javassist/javassist/blob/7302b8b0a09f04d344a26ebe57f29f3db43f2a3e/src/main/javassist/bytecode/AccessFlag.java#L32 ) 。)
249
+ 从反编译后代码可以看出,可变参数在被使用的时候,他首先会创建一个数组,数组的长度就是调用该方法是传递的实参的个数,然后再把参数值全部放到这个数组当中,然后再把这个数组作为参数传递到被调用的方法中。(注:` transient ` 仅在修饰成员变量时有意义,此处 “修饰方法” 是由于在 javassist 中使用相同数值分别表示 ` transient ` 以及 ` vararg ` ,见 [ 此处] ( https://github.com/jboss-javassist/javassist/blob/7302b8b0a09f04d344a26ebe57f29f3db43f2a3e/src/main/javassist/bytecode/AccessFlag.java#L32 ) 。)
250
250
251
251
### 枚举
252
252
@@ -263,7 +263,8 @@ public enum t {
263
263
然后我们使用反编译,看看这段代码到底是怎么实现的,反编译后代码内容如下:
264
264
265
265
``` java
266
- public final class T extends Enum
266
+ // Java编译器会自动将枚举名处理为合法类名(首字母大写): t -> T
267
+ public final class T extends Enum
267
268
{
268
269
private T (String s , int i )
269
270
{
@@ -308,7 +309,7 @@ public final class T extends Enum
308
309
** 内部类之所以也是语法糖,是因为它仅仅是一个编译时的概念,` outer.java ` 里面定义了一个内部类` inner ` ,一旦编译成功,就会生成两个完全不同的` .class ` 文件了,分别是` outer.class ` 和` outer$inner.class ` 。所以内部类的名字完全可以和它的外部类名字相同。**
309
310
310
311
``` java
311
- public class OutterClass {
312
+ public class OuterClass {
312
313
private String userName;
313
314
314
315
public String getUserName () {
@@ -337,10 +338,10 @@ public class OutterClass {
337
338
}
338
339
```
339
340
340
- 以上代码编译后会生成两个 class 文件:` OutterClass $InnerClass.class` 、` OutterClass .class` 。当我们尝试对` OutterClass .class` 文件进行反编译的时候,命令行会打印以下内容:` Parsing OutterClass .class...Parsing inner class OutterClass $InnerClass.class... Generating OutterClass .jad ` 。他会把两个文件全部进行反编译,然后一起生成一个` OutterClass .jad` 文件。文件内容如下:
341
+ 以上代码编译后会生成两个 class 文件:` OuterClass $InnerClass.class` 、` OuterClass .class` 。当我们尝试对` OuterClass .class` 文件进行反编译的时候,命令行会打印以下内容:` Parsing OuterClass .class...Parsing inner class OuterClass $InnerClass.class... Generating OuterClass .jad ` 。他会把两个文件全部进行反编译,然后一起生成一个` OuterClass .jad` 文件。文件内容如下:
341
342
342
343
``` java
343
- public class OutterClass
344
+ public class OuterClass
344
345
{
345
346
class InnerClass
346
347
{
@@ -353,16 +354,16 @@ public class OutterClass
353
354
this . name = name;
354
355
}
355
356
private String name;
356
- final OutterClass this $0 ;
357
+ final OuterClass this $0 ;
357
358
358
359
InnerClass ()
359
360
{
360
- this . this $0 = OutterClass . this ;
361
+ this . this $0 = OuterClass . this ;
361
362
super ();
362
363
}
363
364
}
364
365
365
- public OutterClass ()
366
+ public OuterClass ()
366
367
{
367
368
}
368
369
public String getUserName ()
@@ -385,37 +386,37 @@ public class OutterClass
385
386
386
387
``` java
387
388
// 省略其他属性
388
- public class OutterClass {
389
+ public class OuterClass {
389
390
private String userName;
390
391
......
391
392
class InnerClass {
392
393
......
393
394
public void printOut (){
394
- System . out. println(" Username from OutterClass :" + userName);
395
+ System . out. println(" Username from OuterClass :" + userName);
395
396
}
396
397
}
397
398
}
398
399
399
- // 此时,使用javap -p命令对OutterClass反编译结果 :
400
- public classOutterClass {
400
+ // 此时,使用javap -p命令对OuterClass反编译结果 :
401
+ public classOuterClass {
401
402
private String userName;
402
403
......
403
- static String access$000(OutterClass );
404
+ static String access$000(OuterClass );
404
405
}
405
406
// 此时,InnerClass的反编译结果:
406
- class OutterClass $InnerClass {
407
- final OutterClass this $0 ;
407
+ class OuterClass $InnerClass {
408
+ final OuterClass this $0 ;
408
409
......
409
410
public void printOut ();
410
411
}
411
412
412
413
```
413
414
414
- 实际上,在编译完成之后,inner 实例内部会有指向 outer 实例的引用` this$0 ` ,但是简单的` outer.name ` 是无法访问 private 属性的。从反编译的结果可以看到,outer 中会有一个桥方法` static String access$000(OutterClass ) ` ,恰好返回 String 类型,即 userName 属性。正是通过这个方法实现内部类访问外部类私有属性。所以反编译后的` printOut() ` 方法大致如下:
415
+ 实际上,在编译完成之后,inner 实例内部会有指向 outer 实例的引用` this$0 ` ,但是简单的` outer.name ` 是无法访问 private 属性的。从反编译的结果可以看到,outer 中会有一个桥方法` static String access$000(OuterClass ) ` ,恰好返回 String 类型,即 userName 属性。正是通过这个方法实现内部类访问外部类私有属性。所以反编译后的` printOut() ` 方法大致如下:
415
416
416
417
``` java
417
418
public void printOut() {
418
- System . out. println(" Username from OutterClass :" + OutterClass . access$000(this . this $0 ));
419
+ System . out. println(" Username from OuterClass :" + OuterClass . access$000(this . this $0 ));
419
420
}
420
421
```
421
422
@@ -426,7 +427,7 @@ public void printOut() {
426
427
3 . 匿名内部类、局部内部类通过复制使用局部变量,该变量初始化之后就不能被修改。以下是一个案例:
427
428
428
429
``` java
429
- public class OutterClass {
430
+ public class OuterClass {
430
431
private String userName;
431
432
432
433
public void test (){
@@ -447,10 +448,10 @@ public class OutterClass {
447
448
``` java
448
449
// javap命令反编译Inner的结果
449
450
// i被复制进内部类,且为final
450
- class OutterClass $1Inner {
451
+ class OuterClass $1Inner {
451
452
final int val$i;
452
- final OutterClass this $0 ;
453
- OutterClass $1Inner ();
453
+ final OuterClass this $0 ;
454
+ OuterClass $1Inner ();
454
455
public void printName ();
455
456
}
456
457
@@ -701,7 +702,7 @@ public static transient void main(String args[])
701
702
}
702
703
else
703
704
br. close();
704
- break MISSING_BLOCK_LABEL_113 ;
705
+ break MISSING_BLOCK_LABEL_113 ; // 该标签为反编译工具的生成错误,(不是Java语法本身的内容)属于反编译工具的临时占位符。正常情况下编译器生成的字节码不会包含这种无效标签。
705
706
Exception exception;
706
707
exception;
707
708
if (br != null )
0 commit comments