Java学习:查看java字节码文件

背景:java的源码文件如果需要在jvm上运行,是需要经过编译的,编译的作用就是将.java文件转换为.class文件,.class文件便是字节码文件

首先,字节码文件是二进制文件,所以,我们所谓的查看字节码文件,就是对其进行反向解析,将其解释为人类可以理解的类自然语言以供查看

1.通过常用文本编辑器打开字节码文件,展示的是基本是乱码
vim:


2.通过IDE打开字节码文件,展示的是反编译后的内容(源代码),和实际的源代码有稍许区别,见下图对比:
intellij idea:

反编译后的字节码文件
源码

字节码文件去除了注释,除此之外,代码做了些优化,比如变量定义的赋值处有些变化

// 源码
private Integer smtpPort = 25;
// 编译后
private Integer smtpPort = Integer.valueOf(25);

方法内的代码块也做了些优化

// 源码
public void sendTextMail(MailContent mailContent) {
        if(null != mailContent.getToNames() && mailContent.getToNames().size() >= 1) {
            this.authenticator = new Authenticator() {
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(MailClient.this.username, MailClient.this.password);
                }
            };
            this.session = Session.getInstance(this.props, this.authenticator);
            MimeMessage message = null;

            try {
                message = new MimeMessage(this.session);
                message.setFrom(new InternetAddress(mailContent.getMailFrom()));
                message.setRecipient(RecipientType.TO, new InternetAddress(mailContent.getToNamesString()));
                message.setSubject(mailContent.getTitle());
                message.setText(mailContent.getMailBody());
                message.setSentDate(new Date());
                message.saveChanges();
            } catch (MessagingException var4) {
                var4.printStackTrace();
            }

            this.sendMail(message);
        }
    }
// 编译后
public void sendTextMail(MailContent mailContent) {

        // check mail data
        if (null == mailContent.getToNames() || mailContent.getToNames().size() < 1) {
            return;
        }

        authenticator = new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, password);
            }
        };

        this.session = Session.getInstance(props, authenticator);

        MimeMessage message = null;
        try {
            message = new MimeMessage(session);
            message.setFrom(new InternetAddress(mailContent.getMailFrom()));
            message.setRecipient(Message.RecipientType.TO, new InternetAddress(mailContent.getToNamesString()));
            message.setSubject(mailContent.getTitle());

            message.setText(mailContent.getMailBody()); //pure text mail todo
            message.setSentDate(new Date());//send mail time
            message.saveChanges();//save mail setting
        } catch (MessagingException e) {
            e.printStackTrace();
        }

        this.sendMail(message);
    }

3.通过java反编译工具javap查看字节码文件

内容如下:

Classfile /Users/kisrosen/05_PrivateProject/MailContent.class
  Last modified 2017-2-3; size 2196 bytes
  MD5 checksum d58da5b7eb14cacb8456ec74b829c9ae
  Compiled from "MailContent.java"
public class com.wow.mailutils.MailContent
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #17.#60        // java/lang/Object."<init>":()V
   #2 = Fieldref           #16.#61        // com/wow/mailutils/MailContent.title:Ljava/lang/String;
   #3 = Fieldref           #16.#62        // com/wow/mailutils/MailContent.toNames:Ljava/util/List;
   #4 = Fieldref           #16.#63        // com/wow/mailutils/MailContent.ccNames:Ljava/util/List;
   #5 = Fieldref           #16.#64        // com/wow/mailutils/MailContent.mailFrom:Ljava/lang/String;
   #6 = Fieldref           #16.#65        // com/wow/mailutils/MailContent.mailBody:Ljava/lang/String;
   #7 = Class              #66            // java/lang/StringBuilder
   #8 = Methodref          #7.#60         // java/lang/StringBuilder."<init>":()V
   #9 = InterfaceMethodref #67.#68        // java/util/List.iterator:()Ljava/util/Iterator;
  #10 = InterfaceMethodref #69.#70        // java/util/Iterator.hasNext:()Z
  #11 = InterfaceMethodref #69.#71        // java/util/Iterator.next:()Ljava/lang/Object;
  #12 = Class              #72            // java/lang/String
  #13 = Methodref          #7.#73         // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #14 = String             #74            // ,
  #15 = Methodref          #7.#75         // java/lang/StringBuilder.toString:()Ljava/lang/String;
  #16 = Class              #76            // com/wow/mailutils/MailContent
  #17 = Class              #77            // java/lang/Object
  #18 = Utf8               title
  #19 = Utf8               Ljava/lang/String;
  #20 = Utf8               toNames
  #21 = Utf8               Ljava/util/List;
  #22 = Utf8               Signature
  #23 = Utf8               Ljava/util/List<Ljava/lang/String;>;
  #24 = Utf8               ccNames
  #25 = Utf8               mailFrom
  #26 = Utf8               mailBody
  #27 = Utf8               <init>
  #28 = Utf8               ()V
  #29 = Utf8               Code
  #30 = Utf8               LineNumberTable
  #31 = Utf8               LocalVariableTable
  #32 = Utf8               this
  #33 = Utf8               Lcom/wow/mailutils/MailContent;
  #34 = Utf8               getTitle
  #35 = Utf8               ()Ljava/lang/String;
  #36 = Utf8               setTitle
  #37 = Utf8               (Ljava/lang/String;)V
  #38 = Utf8               getToNames
  #39 = Utf8               ()Ljava/util/List;
  #40 = Utf8               ()Ljava/util/List<Ljava/lang/String;>;
  #41 = Utf8               setToNames
  #42 = Utf8               (Ljava/util/List;)V
  #43 = Utf8               LocalVariableTypeTable
  #44 = Utf8               (Ljava/util/List<Ljava/lang/String;>;)V
  #45 = Utf8               getCcNames
  #46 = Utf8               setCcNames
  #47 = Utf8               getMailFrom
  #48 = Utf8               setMailFrom
  #49 = Utf8               getMailBody
  #50 = Utf8               setMailBody
  #51 = Utf8               getToNamesString
  #52 = Utf8               toName
  #53 = Utf8               toNameString
  #54 = Utf8               Ljava/lang/StringBuilder;
  #55 = Utf8               StackMapTable
  #56 = Class              #66            // java/lang/StringBuilder
  #57 = Class              #78            // java/util/Iterator
  #58 = Utf8               SourceFile
  #59 = Utf8               MailContent.java
  #60 = NameAndType        #27:#28        // "<init>":()V
  #61 = NameAndType        #18:#19        // title:Ljava/lang/String;
  #62 = NameAndType        #20:#21        // toNames:Ljava/util/List;
  #63 = NameAndType        #24:#21        // ccNames:Ljava/util/List;
  #64 = NameAndType        #25:#19        // mailFrom:Ljava/lang/String;
  #65 = NameAndType        #26:#19        // mailBody:Ljava/lang/String;
  #66 = Utf8               java/lang/StringBuilder
  #67 = Class              #79            // java/util/List
  #68 = NameAndType        #80:#81        // iterator:()Ljava/util/Iterator;
  #69 = Class              #78            // java/util/Iterator
  #70 = NameAndType        #82:#83        // hasNext:()Z
  #71 = NameAndType        #84:#85        // next:()Ljava/lang/Object;
  #72 = Utf8               java/lang/String
  #73 = NameAndType        #86:#87        // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #74 = Utf8               ,
  #75 = NameAndType        #88:#35        // toString:()Ljava/lang/String;
  #76 = Utf8               com/wow/mailutils/MailContent
  #77 = Utf8               java/lang/Object
  #78 = Utf8               java/util/Iterator
  #79 = Utf8               java/util/List
  #80 = Utf8               iterator
  #81 = Utf8               ()Ljava/util/Iterator;
  #82 = Utf8               hasNext
  #83 = Utf8               ()Z
  #84 = Utf8               next
  #85 = Utf8               ()Ljava/lang/Object;
  #86 = Utf8               append
  #87 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
  #88 = Utf8               toString
{
  public com.wow.mailutils.MailContent();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 8: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/wow/mailutils/MailContent;

  public java.lang.String getTitle();
    descriptor: ()Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #2                  // Field title:Ljava/lang/String;
         4: areturn
      LineNumberTable:
        line 35: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/wow/mailutils/MailContent;

  public void setTitle(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: putfield      #2                  // Field title:Ljava/lang/String;
         5: return
      LineNumberTable:
        line 39: 0
        line 40: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Lcom/wow/mailutils/MailContent;
            0       6     1 title   Ljava/lang/String;

  public java.util.List<java.lang.String> getToNames();
    descriptor: ()Ljava/util/List;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #3                  // Field toNames:Ljava/util/List;
         4: areturn
      LineNumberTable:
        line 43: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/wow/mailutils/MailContent;
    Signature: #40                          // ()Ljava/util/List<Ljava/lang/String;>;

  public void setToNames(java.util.List<java.lang.String>);
    descriptor: (Ljava/util/List;)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: putfield      #3                  // Field toNames:Ljava/util/List;
         5: return
      LineNumberTable:
        line 47: 0
        line 48: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Lcom/wow/mailutils/MailContent;
            0       6     1 toNames   Ljava/util/List;
      LocalVariableTypeTable:
        Start  Length  Slot  Name   Signature
            0       6     1 toNames   Ljava/util/List<Ljava/lang/String;>;
    Signature: #44                          // (Ljava/util/List<Ljava/lang/String;>;)V

  public java.util.List<java.lang.String> getCcNames();
    descriptor: ()Ljava/util/List;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #4                  // Field ccNames:Ljava/util/List;
         4: areturn
      LineNumberTable:
        line 51: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/wow/mailutils/MailContent;
    Signature: #40                          // ()Ljava/util/List<Ljava/lang/String;>;

  public void setCcNames(java.util.List<java.lang.String>);
    descriptor: (Ljava/util/List;)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: putfield      #4                  // Field ccNames:Ljava/util/List;
         5: return
      LineNumberTable:
        line 55: 0
        line 56: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Lcom/wow/mailutils/MailContent;
            0       6     1 ccNames   Ljava/util/List;
      LocalVariableTypeTable:
        Start  Length  Slot  Name   Signature
            0       6     1 ccNames   Ljava/util/List<Ljava/lang/String;>;
    Signature: #44                          // (Ljava/util/List<Ljava/lang/String;>;)V

  public java.lang.String getMailFrom();
    descriptor: ()Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #5                  // Field mailFrom:Ljava/lang/String;
         4: areturn
      LineNumberTable:
        line 59: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/wow/mailutils/MailContent;

  public void setMailFrom(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: putfield      #5                  // Field mailFrom:Ljava/lang/String;
         5: return
      LineNumberTable:
        line 63: 0
        line 64: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Lcom/wow/mailutils/MailContent;
            0       6     1 mailFrom   Ljava/lang/String;

  public java.lang.String getMailBody();
    descriptor: ()Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #6                  // Field mailBody:Ljava/lang/String;
         4: areturn
      LineNumberTable:
        line 67: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/wow/mailutils/MailContent;

  public void setMailBody(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: putfield      #6                  // Field mailBody:Ljava/lang/String;
         5: return
      LineNumberTable:
        line 71: 0
        line 72: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Lcom/wow/mailutils/MailContent;
            0       6     1 mailBody   Ljava/lang/String;

  public java.lang.String getToNamesString();
    descriptor: ()Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=4, args_size=1
         0: new           #7                  // class java/lang/StringBuilder
         3: dup
         4: invokespecial #8                  // Method java/lang/StringBuilder."<init>":()V
         7: astore_1
         8: aload_0
         9: getfield      #3                  // Field toNames:Ljava/util/List;
        12: invokeinterface #9,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
        17: astore_2
        18: aload_2
        19: invokeinterface #10,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
        24: ifeq          53
        27: aload_2
        28: invokeinterface #11,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
        33: checkcast     #12                 // class java/lang/String
        36: astore_3
        37: aload_1
        38: aload_3
        39: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        42: pop
        43: aload_1
        44: ldc           #14                 // String ,
        46: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        49: pop
        50: goto          18
        53: aload_1
        54: invokevirtual #15                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        57: areturn
      LineNumberTable:
        line 76: 0
        line 78: 8
        line 80: 37
        line 81: 43
        line 82: 50
        line 84: 53
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
           37      13     3 toName   Ljava/lang/String;
            0      58     0  this   Lcom/wow/mailutils/MailContent;
            8      50     1 toNameString   Ljava/lang/StringBuilder;
      StackMapTable: number_of_entries = 2
        frame_type = 253 /* append */
          offset_delta = 18
          locals = [ class java/lang/StringBuilder, class java/util/Iterator ]
        frame_type = 250 /* chop */
          offset_delta = 34
}
SourceFile: "MailContent.java"

对应源码如下:

// 源码
package com.wow.mailutils;

import java.util.List;

/**
 * Created by kisrosen on 17/1/11.
 */
public class MailContent {
    /**
     * Mail Title
     */
    private String title;

    /**
     * Mail Destination List
     */
    private List<String> toNames;

    /**
     * Mail Copyto List
     */
    private List<String> ccNames;

    /**
     * Who send the mail
     */
    private String mailFrom;

    /**
     * Mail Body Content
     */
    private String mailBody;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public List<String> getToNames() {
        return toNames;
    }

    public void setToNames(List<String> toNames) {
        this.toNames = toNames;
    }

    public List<String> getCcNames() {
        return ccNames;
    }

    public void setCcNames(List<String> ccNames) {
        this.ccNames = ccNames;
    }

    public String getMailFrom() {
        return mailFrom;
    }

    public void setMailFrom(String mailFrom) {
        this.mailFrom = mailFrom;
    }

    public String getMailBody() {
        return mailBody;
    }

    public void setMailBody(String mailBody) {
        this.mailBody = mailBody;
    }

    public String getToNamesString()
    {
        StringBuilder toNameString = new StringBuilder();

        for (String toName : this.toNames)
        {
            toNameString.append(toName);
            toNameString.append(",");
        }

        return toNameString.toString();
    }
}

4.通过jclasslib查看字节码文件
jclasslib不但是一个字节码阅读器而且还包含一个类库允许开发者读取,修改,写入Java Class文件与字节码。

由于mac安装jclasslib需要jdk1.6,比较麻烦,我直接通过intellij idea安装jclasslib的插件:

intellij idea的jclasslib插件

安装插件后重启intellij idea,在idea中打开一个java文件,此时View菜单上会有show bytecode in jclasslib的菜单

jclasslib显示内容如下(和javap工具显示的相同,只是可视化程度更高):

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,511评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,495评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,595评论 0 225
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,558评论 0 190
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,715评论 3 270
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,672评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,112评论 2 291
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,837评论 0 181
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,417评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,928评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,316评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,773评论 2 234
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,253评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,827评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,440评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,523评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,583评论 2 249

推荐阅读更多精彩内容