Skip to content

Commit 7aed1c8

Browse files
authored
Merge pull request #2713 from Ka1Yann/main
修正"Java 语法糖详解"中的错别字
2 parents e225232 + 8401399 commit 7aed1c8

File tree

1 file changed

+23
-22
lines changed

1 file changed

+23
-22
lines changed

docs/java/basis/syntactic-sugar.md

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ public static transient void print(String strs[])
246246
}
247247
```
248248

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)。)
250250

251251
### 枚举
252252

@@ -263,7 +263,8 @@ public enum t {
263263
然后我们使用反编译,看看这段代码到底是怎么实现的,反编译后代码内容如下:
264264

265265
```java
266-
public final class T extends Enum
266+
//Java编译器会自动将枚举名处理为合法类名(首字母大写): t -> T
267+
public final class T extends Enum
267268
{
268269
private T(String s, int i)
269270
{
@@ -308,7 +309,7 @@ public final class T extends Enum
308309
**内部类之所以也是语法糖,是因为它仅仅是一个编译时的概念,`outer.java`里面定义了一个内部类`inner`,一旦编译成功,就会生成两个完全不同的`.class`文件了,分别是`outer.class``outer$inner.class`。所以内部类的名字完全可以和它的外部类名字相同。**
309310

310311
```java
311-
public class OutterClass {
312+
public class OuterClass {
312313
private String userName;
313314

314315
public String getUserName() {
@@ -337,10 +338,10 @@ public class OutterClass {
337338
}
338339
```
339340

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`文件。文件内容如下:
341342

342343
```java
343-
public class OutterClass
344+
public class OuterClass
344345
{
345346
class InnerClass
346347
{
@@ -353,16 +354,16 @@ public class OutterClass
353354
this.name = name;
354355
}
355356
private String name;
356-
final OutterClass this$0;
357+
final OuterClass this$0;
357358

358359
InnerClass()
359360
{
360-
this.this$0 = OutterClass.this;
361+
this.this$0 = OuterClass.this;
361362
super();
362363
}
363364
}
364365

365-
public OutterClass()
366+
public OuterClass()
366367
{
367368
}
368369
public String getUserName()
@@ -385,37 +386,37 @@ public class OutterClass
385386

386387
```java
387388
//省略其他属性
388-
public class OutterClass {
389+
public class OuterClass {
389390
private String userName;
390391
......
391392
class InnerClass{
392393
......
393394
public void printOut(){
394-
System.out.println("Username from OutterClass:"+userName);
395+
System.out.println("Username from OuterClass:"+userName);
395396
}
396397
}
397398
}
398399

399-
// 此时,使用javap -p命令对OutterClass反编译结果
400-
public classOutterClass {
400+
// 此时,使用javap -p命令对OuterClass反编译结果
401+
public classOuterClass {
401402
private String userName;
402403
......
403-
static String access$000(OutterClass);
404+
static String access$000(OuterClass);
404405
}
405406
// 此时,InnerClass的反编译结果:
406-
class OutterClass$InnerClass {
407-
final OutterClass this$0;
407+
class OuterClass$InnerClass {
408+
final OuterClass this$0;
408409
......
409410
public void printOut();
410411
}
411412

412413
```
413414

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()`方法大致如下:
415416

416417
```java
417418
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));
419420
}
420421
```
421422

@@ -426,7 +427,7 @@ public void printOut() {
426427
3. 匿名内部类、局部内部类通过复制使用局部变量,该变量初始化之后就不能被修改。以下是一个案例:
427428

428429
```java
429-
public class OutterClass {
430+
public class OuterClass {
430431
private String userName;
431432

432433
public void test(){
@@ -447,10 +448,10 @@ public class OutterClass {
447448
```java
448449
//javap命令反编译Inner的结果
449450
//i被复制进内部类,且为final
450-
class OutterClass$1Inner {
451+
class OuterClass$1Inner {
451452
final int val$i;
452-
final OutterClass this$0;
453-
OutterClass$1Inner();
453+
final OuterClass this$0;
454+
OuterClass$1Inner();
454455
public void printName();
455456
}
456457

@@ -701,7 +702,7 @@ public static transient void main(String args[])
701702
}
702703
else
703704
br.close();
704-
break MISSING_BLOCK_LABEL_113;
705+
break MISSING_BLOCK_LABEL_113; //该标签为反编译工具的生成错误,(不是Java语法本身的内容)属于反编译工具的临时占位符。正常情况下编译器生成的字节码不会包含这种无效标签。
705706
Exception exception;
706707
exception;
707708
if(br != null)

0 commit comments

Comments
 (0)