1. 程式人生 > >內部類的反編譯分析和總結

內部類的反編譯分析和總結

內部類:是指在類的內部又定義了一個類。根據位置的不同可以分為成員內部類和區域性內部類。

成員內部類

在成員變數的位置定義一個類。
1. 依賴外部類物件存在
2. 可以訪問外部類的成員變數和成員方法。

訪問方式:
1. 直接訪問,直接使用變數名和方法名
2. 通過外部類名.this.變數名/方法名

package test;

public class Outer {
    private int num = 1;
    public void before() {
        System.out.println("before");
    }
    // 成員變數,成員方法,成員內部類是一樣
public class Inner{ private int count = 2; private int num = 2; public void speak() { System.out.println(num); // 2 System.out.println(Outer.this.num); // 1 before(); // before System.out.println(count); // 2
} public Inner() { super(); } } }

編譯生成Outer.class和Outer$Inner.class兩個class檔案
用javap -c Outer$Inner.class 命令反編譯檢視

public class test.Outer$Inner {
  final test.Outer this$0;

  public void speak();
    Code:
       0: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
3: aload_0 4: getfield #19 // Field num:I 7: invokevirtual #21 // Method java/io/PrintStream.println:(I)V 10: getstatic #13 // Field java/lang/System.out:Ljava/io/PrintStream; 13: aload_0 14: getfield #27 // Field this$0:Ltest/Outer; 17: invokestatic #29 // Method test/Outer.access$0:(Ltest/Outer;)I 20: invokevirtual #21 // Method java/io/PrintStream.println:(I)V 23: aload_0 24: getfield #27 // Field this$0:Ltest/Outer; 27: invokevirtual #35 // Method test/Outer.before:()V 30: getstatic #13 // Field java/lang/System.out:Ljava/io/PrintStream; 33: aload_0 34: getfield #38 // Field count:I 37: invokevirtual #21 // Method java/io/PrintStream.println:(I)V 40: return public test.Outer$Inner(test.Outer); Code: 0: aload_0 1: aload_1 2: putfield #27 // Field this$0:Ltest/Outer; 5: aload_0 6: invokespecial #46 // Method java/lang/Object."<init>":()V 9: aload_0 10: iconst_2 11: putfield #38 // Field count:I 14: aload_0 15: iconst_2 16: putfield #19 // Field num:I 19: return }

在編譯成class檔案的過程,編譯器會自己在Inner類中生成一個指向父類物件的引用,並且只含一個有外部類型別的引數的構造方法。
所以看到這就明白了為何內部類能訪問外部類物件的成員變數和方法,並且依賴外部類物件存在。

靜態成員內部類

在成員內部類的基礎上加上了static關鍵字修飾
1.不依賴外部類物件存在
2.只能訪問外部類的靜態成員變數和靜態方法。
訪問方式:
1. 直接訪問,直接使用變數名和方法名
2. 通過外部類名.變數名/方法名

package test;

public class Outer {

    private static int num = 1;
    public void before() {
        System.out.println("before");
    }
    // 靜態成員內部類
    public static class Inner{
        private int count = 2;
        private int num = 2;
        public void speak() {
            System.out.println(num);                // 2
            System.out.println(Outer.num);          // 通過類名的方式訪問
            System.out.println(count);              // 2
        }
        public Inner() {
            super();
        }
    }
}

建立內部類物件: Outer.Inner inner = new Outer().new Inner();
編譯生成Outer.class和Outer$Inner.class兩個class檔案
用javap -c Outer$Inner.class 命令反編譯檢視

public class test.Outer$Inner {
  public void speak();
    Code:
       0: getstatic     #11                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: aload_0
       4: getfield      #17                 // Field num:I
       7: invokevirtual #19                 // Method java/io/PrintStream.println:(I)V
      10: getstatic     #11                 // Field java/lang/System.out:Ljava/io/PrintStream;
      13: invokestatic  #25                 // Method test/Outer.access$0:()I
      16: invokevirtual #19                 // Method java/io/PrintStream.println:(I)V
      19: getstatic     #11                 // Field java/lang/System.out:Ljava/io/PrintStream;
      22: aload_0
      23: getfield      #31                 // Field count:I
      26: invokevirtual #19                 // Method java/io/PrintStream.println:(I)V
      29: return

  public test.Outer$Inner();
    Code:
       0: aload_0
       1: invokespecial #38                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: iconst_2
       6: putfield      #31                 // Field count:I
       9: aload_0
      10: iconst_2
      11: putfield      #17                 // Field num:I
      14: return
}

發現靜態成員內部類沒有外部類物件的引用,所以不能訪問外部類物件的非靜態的成員變數和方法。它是相當一個獨立的類,但限制了訪問方式,要通過外部類訪問內部類。此時內部類相當於外部類的靜態成員.
建立內部類物件:Outer.Inner inner = new Outer.Inner();

成員內部類

在方法中宣告的一個類

package test;

public class Outer2 {
    private int num = 1;

    public void print() {
        System.out.println("Outer的print");
    }

    public void fun() {

        // 區域性內部類
        class Inner{
            public void print() {
                System.out.println("Inner的print");
            }
            public void test() {
                Outer2.this.print();    // 呼叫外部類物件的方法
            }
        }
        new Inner().print();
        new Inner().test();
    }
    public static void main(String[] args) {
        Outer2 outer2 = new Outer2();
        outer2.fun();
    }
}

執行結果如下

Inner的print
Outer的print

開啟反編譯工具檢視下程式碼

class test.Outer2$1Inner {
  final test.Outer2 this$0;

  test.Outer2$1Inner(test.Outer2);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #10                 // Field this$0:Ltest/Outer2;
       5: aload_0
       6: invokespecial #12                 // Method java/lang/Object."<init>":()V
       9: return

  public void print();
    Code:
       0: getstatic     #20                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #26                 // String Inner的print
       5: invokevirtual #28                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return

  public void test();
    Code:
       0: aload_0
       1: getfield      #10                 // Field this$0:Ltest/Outer2;
       4: invokevirtual #35                 // Method test/Outer2.print:()V
       7: return
}

同樣區域性內部類含有外部類物件的引用並且有且僅有一個含有外部類型別的引數的構造方法,和成員內部類是一樣的。

和成員內部類的區別就是,成員內部類物件可以在其他的類中建立,而區域性內部類只能在方法宣告並建立,作用域在一個方法中。

相關推薦

部類編譯分析總結

內部類:是指在類的內部又定義了一個類。根據位置的不同可以分為成員內部類和區域性內部類。 成員內部類 在成員變數的位置定義一個類。 1. 依賴外部類物件存在 2. 可以訪問外部類的成員變數和成員方法。 訪問方式: 1. 直接訪問,直接使用變數

談談對4種部類的理解,使用場景分析

談談你對內部類的位元組碼和實戰使用場景理解 綜合技術 2017-12-01 閱讀原文    讀完本文你將瞭解: [TOC] 通過反編譯介紹四種內部類 結合實戰介紹內部類的使用場景 背景介紹 我們做這個活動,除了要保證知識點的全面、完整,還想要讓每一篇文章都有

部類、執行緒併發的個人總結

內部類    內部類分為:普通內部類、程式塊中的內部類、靜態內部類、匿名內部類。    普通內部類必須在宿主構造例項時才能構造,普通內部類保有宿主的引用可以不受限制的訪問宿主的任何成員。   常見用法:    1:利用內部類隱藏實現介面    當程式中某些邏輯要開發新的類來

Java部類之訪問許可權編譯效率

問題1: elementData的註釋的意思是,非私有化以簡化巢狀類的訪問,但巢狀類可以透明地訪問外圍類的所有成員,如何理解這裡的簡化? 為什麼不宣告為private呢? 通過檢視反編譯檢視位元組碼解決了問題: 虛擬機器不知道類的分組情況,會在類中提供

VC運行庫版本不同導致鏈接.LIB靜態庫時發生重復定義問題的一個案例分析總結

修改 borde 並且 release 鏈接 部分 sdn 托管代碼 兩個 MSDN中對於在不同的配置下Link的LIB作了說明: C Runtime Library: 開關 對應的庫 版本 /MD

Java中,部類的概述部類的訪問特點部類的分類(部類的位置)

back 外部 mage 對象 post info bsp 一個 strong 內部類的概述:   把類定義在另一個類的內部,該類就被稱為內部類。   舉例:把類B定義在類A中,類B就被稱為內部類。 內部類的訪問特點:   A:內部類可以直接訪問外部類的成員,包括

javaSE_day8_構造方法_super關鍵字_final關鍵字_static關鍵字_部類_訪問許可權修飾符_程式碼塊_自定義資料型別

1.構造方法 作用:用來給類的成員進行初始化操作 定義格式:許可權  方法名(引數列表){ ... } //注意:方法的名字必須和類名完全一致,構造方法不允許寫返回值型別,void也不能寫 構造方法在什麼時候執行呢:在new物件的時候,自動執行,且

jadx編譯—下載使用(傻瓜教程,非常詳細)

一、在GitHub上直接下載 https://github.com/skylot/jadx 可以下這個版本: 二、執行圖形化介面 1、將zip檔案解壓後定位到在lib資料夾中,在此處開啟命令列 2、執行jadx-gui-0.7.1.jar(前提是已經裝好了JDK1

Java非靜態部類外部this物件final型別詳解

1. 非靜態內部類是如何引用外部類this物件的 Java內部類分為靜態內部類和非靜態內部類。它們有一個比較大的區別在於,非靜態內部類擁有外部類的this物件的引用,從而使得非靜態內部類可以訪問外部類的成員函式,成員變數。這個結論我們大家都比較清楚,那麼原理大家都懂嗎?這篇文章我講通

記一次某App編譯分析

每次尋找漏洞的時候,我都喜歡從抓包開始 噢噢,這裡有點尷尬~~請求和返回的資料都進行了加密處理,這波操作我挺喜歡的,證明人家公司的開發人員還是有點安全意識的,不過沒有關係,他有張良計,我有過牆梯,先反編譯一波看看,使用的工具是 jadx 很明顯,app用了360加固

簡單談談我對Java 中 Class.forName()、Class.class、例項物件.getClass() 三種獲取位元組碼物件的理解?(內含程式碼分析總結)

首先得明白的知識點: 1靜態屬性初始化載入類的時候初始化( 只會初始化一次),而非靜態屬性的初始化就是new類例項物件的時候初始化的 2三種獲取位元組碼物件的共同點就是都會預先的判斷記憶體是否已經載入此類,弱沒有載入,則會把.class檔案裝入到記憶體,若是載入了,則會根據class檔案生成例

常見亂碼問題分析總結

夏 懷英 和 David Chen 2018 年 1 月 17 日釋出 在我們的日常工作生活中一定碰到過下面的情況: 場景 1: 安裝完某個軟體後,看到的安裝程式變成類似這樣的一組字元" µç×ÓË°Îñ¾ÖÖ¤ÊéÇý¶¯¼°·þÎñƽ̨"圖 1 所示的樣子; 圖

Android安卓APK編譯分析、簡單修改內容、二次打包簽名

一、需求:想要修改一個apk裡面一串字串 環境: dex2jar----https://github.com/pxb1988/dex2jar/ JD-GUI----http://jd.benow.ca/ jdk1.8.0環境 二、先反編譯解包分析: (明

【mpeg2】mpeg1、mpeg2mpeg4標準對比分析總結

Date: 2018.11.2 mpeg1、mpeg2和mpeg4標準對比 0、參考 1、編解碼流程     MPEG-1標準主要採用基於插值的運動補償預測+DCT+量化+VLC熵編碼的技術;MPEG-2標準在MPEG-1的基礎上增加了Scan過程並且碼

Android 編譯——dex2jar jd-gui 的安裝與使用

步驟一:解壓縮Apk 將需要破解的Apk的字尾修改為zip,然後解壓縮,可以得到assets檔案、res資原始檔、AndroidManifest.xml配置檔案以及一個classes.dex檔案。如下圖: 其中classes.dex檔案非常重要,它是我們得到Java類的基礎。

java部類回顧之一般部類實現多繼承封裝性

本文的標題可能有一定的誤導性,並不是說一般內部類就能實現多繼承,顯然這是不可能的。真正的意思是通過多繼承來實現我們期望中的多繼承的功能。 這裡就拿人類來舉例吧,人(Person)是一種生物(biology),而且是可移動(Moveable)的生物。我們可以定義如下兩個類:

部類實現多繼承封裝性

本文的標題可能有一定的誤導性,並不是說一般內部類就能實現多繼承,顯然這是不可能的。真正的意思是通過多繼承來實現我們期望中的多繼承的功能。 這裡就拿人類來舉例吧,人(Person)是一種生物(biology),而且是可移動(Moveable)的生物。我們可以定義如下兩個類

部類序列化問題(fastjson exception: create instance error)

一、問題 專案開發過程中遇到了JSON反序列化問題(JSONException: create instance error),問題如下: ... com.alibaba.fastjson.JSONException: create instance e

靜態方法中不能new部類的例項物件的總結

原文 class Test{ public void main(String[] args){ A testA=new A(); //這裡會出現問題 new Thread(new Runnable(){ public void run(){

VC執行庫版本不同導致連結.LIB靜態庫時發生重複定義問題的一個案例分析總結

from:http://blog.csdn.net/ithzhang/article/details/13170047 Background MSDN中對於在不同的配置下Link的LIB作了說明: C Runtime Library: 開關 對應的庫