查看java字节码文件
2017-02-05 本文已影响1225人
测试你个头
背景: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工具显示的相同,只是可视化程度更高):