本地臨時變量 基本類型
final int x = 10; new Runnable() { @Override public void run() { System.out.println(x); } }.run();
當輸出內(nèi)部類字節(jié)碼(javap -p -s -c -v)時,如下所示:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: bipush 10 5: invokevirtual #3 // Method java/io/PrintStream.println:(I)V 8: return
可以看出,此常量值直接被寫在內(nèi)部類的臨時變量中,即相當于進行了一次變量copy。
本地臨時變量 引用類型
final T t = new T(); new Runnable() { @Override public void run() { System.out.println(t); } }.run();
字節(jié)碼變?yōu)槿缦滤荆?/p>
final T val$t; flags: ACC_FINAL, ACC_SYNTHETIC T$1(T); Signature: (LT;)V //構(gòu)建函數(shù)的字節(jié)碼 0: aload_0 1: aload_1 2: putfield #1 // Field val$t:LT; 5: aload_0 6: invokespecial #2 // Method java/lang/Object."<init>":()V 9: return //main函數(shù)字節(jié)碼 0: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 3: aload_0 4: getfield #1 // Field val$t:LT; 7: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V 10: return
可以看出,這時自動生成了一個帶有1個參數(shù)的構(gòu)造函數(shù),并且將相應的t值作為參數(shù)傳遞到內(nèi)部類當中,同時設(shè)定final語義,即不能被內(nèi)部類修改。
上面的是無參構(gòu)造函數(shù),如果是一個有參數(shù)的內(nèi)部類呢,如下所示:
Thread thread = new Thread("thread-1") { @Override public void run() { System.out.println(t); } };
生成的字節(jié)碼如下:
T$1(java.lang.String, T); Signature: (Ljava/lang/String;LT;)V
可以看出,編譯器將自動對原來調(diào)用的構(gòu)造函數(shù)進行了修改,將原來只需要1個參數(shù)的構(gòu)造函數(shù) 修改為傳2個參數(shù),并且同時將相應的t傳遞進去。
引用字段,基本類型
int t = 3; private void xx() { new Runnable() { @Override public void run() { System.out.println(t); } }.run(); }
生成的字節(jié)碼如下:
T$1(T); Signature: (LT;)V flags: Code: stack=2, locals=2, args_size=2 0: aload_0 1: aload_1 2: putfield #1 // Field this$0:LT; 5: aload_0 6: invokespecial #2 // Method java/lang/Object."<init>":()V 9: return
這里并沒有如臨時變量那樣,直接在內(nèi)部類中進行常量定義。為什么?因為這里的t對象隨時可能被修改。
引用字段,引用類型
final String t = new String("abc"); private void xx() { new Runnable() { @Override public void run() { System.out.println(t); } }.run(); }
生成字節(jié)碼如下:
final T this$0; Signature: LT; T$1(T); //內(nèi)部類構(gòu)造函數(shù) 0: aload_0 1: aload_1 2: putfield #1 // Field this$0:LT; 5: aload_0 6: invokespecial #2 // Method java/lang/Object."<init>":()V 9: return
這里,在內(nèi)部類的構(gòu)造函數(shù)中,直接將外部類的this傳遞進來了,因此在內(nèi)部類的run方法中,對于t,將直接兩層getField進行調(diào)用,即可以拿到相應的信息。如下所示:
0: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 3: aload_0 4: getfield #1 // Field this$0:LT; 7: getfield #4 // Field T.t:Ljava/lang/String; 10: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 13: return
引用類型,引用類型,static字段
static String t = new String("abc"); private void xx() { new Runnable() { @Override public void run() { System.out.println(t); } }.run(); }
字節(jié)碼如下:
final T this$0; Signature: LT; flags: ACC_FINAL, ACC_SYNTHETIC T$1(T); Signature: (LT;)V //構(gòu)造函數(shù)字節(jié)碼 0: aload_0 1: aload_1 2: putfield #1 // Field this$0:LT; 5: aload_0 6: invokespecial #2 // Method java/lang/Object."<init>":()V 9: return //run方法字節(jié)碼 0: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 3: getstatic #4 // Field T.t:Ljava/lang/String; 6: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 9: return
可以看出,即使是引用static字段,在內(nèi)部類中仍然會保留外部類的引用,即達到引用目的。同時,在run方法內(nèi)部,因為是static字段,因此將不再使用getField,而是使用getStatic來進行相應字段的引用。
總結(jié)
在整個內(nèi)部類字節(jié)碼的生成規(guī)則中,主要采用了修改構(gòu)造函數(shù)的方式來將需要在整個內(nèi)部類中引用的變量進行參數(shù)傳遞。并且,因為是內(nèi)部類,構(gòu)造函數(shù)是已知的,可以隨意的修改。針對特定的場景,可以進行一定的優(yōu)化,如常量化(臨時變量基本類型)。
因為在整個JVM層,并沒有針對內(nèi)部類作特殊的處理,因此這些處理手法都是在編譯層進行處理的。同時,在語言層,針對這些生成的信息進行指定的說明。如SYNTHETIC語義。
在反射字段Member層,定義了如下方法:
/** * Returns {@code true} if this member was introduced by * the compiler; returns {@code false} otherwise. * * @return true if and only if this member was introduced by * the compiler. * @jls 13.1 The Form of a Binary * @since 1.5 */ public boolean isSynthetic();
即此信息是由編譯器引入的。
了解這些對于整個語言層有一定的理解意義,但并不代表將來這些不會會改變,了解一些實現(xiàn)細節(jié)有助于自己在代碼實現(xiàn)層有進一步的思考空間,并不局限于之前所了解的信息。

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)
