1. 程式人生 > >使用ASM來書寫Java程式碼-2

使用ASM來書寫Java程式碼-2

1.   類:
a)        陣列:
                      i.              建立:
mv.visitInsn(ICONST_3);
mv.visitIntInsn(NEWARRAY, T_INT);
mv.visitVarInsn(ASTORE, 1);      //   將陣列引用存到區域性變數棧1號的位置
 
等價於:
int[] a = new int[3];
 
                   ii.              取值:
mv.visitVarInsn(ALOAD, 1);       //   陣列引用在區域性變數棧1號的位置
mv.visitInsn(ICONST_1);
mv.visitInsn(IALOAD);
mv.visitVarInsn(ISTORE, 2);
 
等價於:
int b = a[1];
 
                iii.              賦值:
mv.visitVarInsn(ALOAD, 1);
mv.visitInsn(ICONST_1);
mv.visitInsn(ICONST_2);
mv.visitInsn(IASTORE);
 
等價於:
a[1] = 2;
 
b)        建構函式:
                      i.              <init>:
1.        建立:
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", ()V");
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
 
說明:建構函式<init>在執行時,需要首先執行父類的建構函式或者類內部其他構造
函式。
 
2.        呼叫:
mv.visitTypeInsn(NEW, "asm/A");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, "asm/A", "<init>", "()V");
mv.visitVarInsn(ASTORE, 1);


等價於:
A a = new A();
 
說明:在初始化一般物件時,我們需要先呼叫NEW指令,來建立該物件例項。而由於
後續的INVOKESPECIAL指令是呼叫類的建構函式,而該指令執行完以後,對物件的引
用將從棧中彈出,所以在NEW指令執行完以後,INVOKESPECIAL指令執行以前,我們
需要呼叫DUP指令,來增加物件引用的副本。
 
                   ii.              <clinit>:
1.        建立:
MethodVisitor mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
mv.visitCode();
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out",
"Ljava/io/PrintStream;");
mv.visitLdcInsn("hello world");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",
"(Ljava/lang/String;)V");
mv.visitInsn(RETURN);
mv.visitMaxs(2, 0);
mv.visitEnd();
 
等價於:
static {
System.out.println("hello world");
}
 
2.        呼叫:<clinit>在類被載入時自動呼叫。
 
c)        欄位:
                      i.              一般欄位:
1.        建立:
FieldVisitor fv = cw.visitField(ACC_PRIVATE, "a", "I", null, null);
fv.visitEnd();
 
等價於:
private int a;
 
2.        讀取:讀取類當中名字為a,型別為int的欄位的值。
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, "asm/A", "a", "I");
 
3.        設定:
mv.visitVarInsn(ALOAD, 0);
mv.visitInsn(ICONST_2);
mv.visitFieldInsn(PUTFIELD, "asm/A", "a", "I");
 
等價於:
a = 2;
 
                   ii.              靜態欄位:
1.        建立:
FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_STATIC, "a", "I", null,
null);
fv.visitEnd();
 
等價於:
private static int a;
 
2.        讀取:
mv.visitFieldInsn(GETSTATIC, "asm/A", "a", "I");
 
3.        設定:
mv.visitInsn(ICONST_2);
mv.visitFieldInsn(PUTSTATIC, "asm/A", "a", "I");




等價於:
a = 2;
 
d)        方法:
                      i.              介面方法:
1.        定義:
mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "getA", "()V", null, null);
mv.visitEnd();
 
2.        呼叫:
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEINTERFACE, "asm/IA", "getA", "()V");
 
等價於:
public interface IA{
     public void geA();
}
public class A implements IA{
     public void geA(){…}
}
 
IA a = new A();
a.getA();
 
                   ii.              一般方法:
1.        定義:
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "getA", "()V", null, null);
mv.visitCode();
mv.visitInsn(RETURN);
mv.visitMaxs(0, 1);
mv.visitEnd();
 
等價於:
public void getA() {}
 
2.        呼叫:
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEVIRTUAL, "asm/A", "getA", "()V");
 
等價於:
A a = new A():
a.getA();
 
                iii.              靜態方法:
1.        定義:
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "getA", "()V",
null, null);
mv.visitCode();
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
 
等價於:
public static void getA() {}
 
2.        呼叫:
mv.visitMethodInsn(INVOKESTATIC, "asm/A", "getB", "()V");
 
等價於:
A.getB();
    
                   iv.              說明:一般方法比靜態方法在宣告和呼叫時均要多傳入一個this引用作為引數。另外,當使用INVOKESPECIAL來呼叫方法時,虛擬機器將直接根據指令當中所指明的類型別來呼叫方法;而當使用INVOKEVIRTUAL來呼叫方法時,虛擬機器將根據例項的實際型別來呼叫方法。
 
e)        異常處理:
                      i.              宣告:
mv.visitTryCatchBlock(l0, l1, l1, "java/lang/Exception");
mv.visitLabel(l0);
mv.visitLabel(l1);

等價於:
try {

} catch (Exception e) {

}
 
說明:在visitTryCatchBlock()當中,第一,二,三個引數均是Label例項,其中一,二表示try塊的範圍,三則是catch塊的開始位置。而第四個引數則是異常型別。而當異常發生時,JVM將會將異常例項置於執行棧的
 
轉載:http://blog.sina.com.cn/s/blog_4b38e200010008tp.html

相關推薦

使用ASM書寫Java程式碼2

1.   類: a)        陣列:                       i.              建立: mv.visitInsn(ICONST_3); mv.visitIntInsn(NEWARRAY, T_INT); mv.visitVarIns

90% 的 Java 程式設計師都說不上的為何 Java 程式碼越執行越快(2)- TLAB預熱

經常聽到 Java 效能不如 C/C++ 的言論,也經常聽說 Java 程式需要預熱,**那麼其中主要原因是啥呢**? 面試的時候談到 JVM,也有很多面試官喜歡問,**為啥 Java 程式越執行越快呢**? 一般人都能回答上來,類載入,快取預熱等等,但是深入下去,**最重要的卻沒有答上來**,今天本系列

CCF認證201803-2 碰撞的小球 java程式碼實現。

問題描述   數軸上有一條長度為L(L為偶數)的線段,左端點在原點,右端點在座標L處。有n個不計體積的小球線上段上,開始時所有的小球都處在偶數座標上,速度方向向右,速度大小為1單位長度每秒。   當小球到達線段的端點(左端點或右端點)的時候,會立即向相反的方向移動,速度大小仍然為原來大小。   當兩個小

所謂的網頁爬蟲用java程式碼實現,此程式碼適合在maven專案中使用中使用,因為,程式碼中的類所對應的依賴可以讓maven下載。

//獲得httpClient物件 CloseableHttpClient httpClient = HttpClients.createDefault(); //url公司域名隨便 String url = "https://www.baidu.co

資料結構2--線性表(java程式碼實現線性表的鏈式儲存)

1.鏈式儲存       2.分析       每個節點為一個物件,該物件包含資料域和指標域        整條單鏈表為一個物件,他和節點物件進行組合。  3.

Java筆試題——2的100次方,不用大資料類(Biginteger)解答

Java筆試題——2的100次方,不用大資料類(Biginteger)來解答 package cn.hncu.offer; public class Two100 { public static void main(String[] args) { int a[]=new int[1];//

開發者筆記3 | Java 程式碼規約第 2

返回規約清單列表 規約型別:程式設計規約 - 命名風格 規約級別:強制 規約描述:程式碼中的命名嚴禁使用拼音與英文混合的方式,更不允許直接使用中文的方式 說明: 正確的英文拼寫和語法可以讓閱讀者易於理解,避免歧義。注意,即使純拼音命名方式,也要避免採用。 正例: alibab

開發者筆記2 | Java 程式碼規約第1條

返回規約清單列表 規約型別:程式設計規約 - 命名風格 規約級別:強制 規約描述:程式碼中的命名均不能以下劃線或美元符號開始,也不能以下劃線或美元符號結束 反例: \_name / \_\_name / $name / name_ / name$ / name__

zookeeper - 通過java程式碼連線zookeeper(2)

首先建立一個Maven專案 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www

Java 7: 全面教程-1.2 Java程式碼規格

1.2 Java程式碼規格 寫正確的可執行的Java程式固然重要,但是寫出的程式碼方便閱讀和維護也是相當重要的。普遍相信一個軟體80%的時間都花在維護上。而且,程式設計師的變動率非常的高,所以很有可能是別人在維護你的程式碼。如果你留下的程式原始碼是清楚且簡單易懂的,不管是誰都會非常感謝你。 讓

Java程式碼中如何通過 http上傳檔案

例子程式碼如下 package example.filetransfer; import java.io.*; import java.net.*; import java.util.*; public class HttpRequestUtil { /** * 傳送ge

Android逆向-java程式碼基礎(2

0x00 前言 由於是對java語言的複習,所以進度會很快,而且會以smali為主,java只是順便提一下,如果對java有興趣詳細研究的,可以下載pdf仔細的看。 這篇主要涉及到基本資料型別,int,float,char,以及運算。 連結:ht

MongoDB-JAVA-Driver 3.2版本常用程式碼全整理(3)

MongoDB的3.x版本Java驅動相對2.x做了全新的設計,類庫和使用方法上有很大區別。例如用Document替換BasicDBObject、通過Builders類構建Bson替代直接輸入$命令等,本文整理了基於3.2版本的常用增刪改查操作的使用方法。為了避免冗長的篇幅

2)Hadoop核心 -- java程式碼對MapReduce的例子1

案例一:wordcount字數統計功能 1.1 先準備兩個txt檔案,並上傳到hdfs上 test1.txt hello zhangsan lisi nihao hai zhangsan nihao lisi x xiaoming test2.txt zha

2)Hadoop核心-java程式碼對MapReduce的操作

上一篇檔案介紹了java程式碼怎麼操作hdfs檔案的,hdfs理念“就是一切皆檔案”,我們現在搞定了怎麼使用java上傳下載等操作了接下來就要處理檔案了,hadoop的mapreduce模組。 一、Hadoop Map/Reduce框架        

使用java程式碼實現dvd管理系統

import java.util.Scanner; /*  * DVD管理系統  * 陣列的長度是固定的,當在記憶體中開闢了空間後  * 長度都不能變,後面學習到集合框架的時候,長度是可變化的。  */ public class D

使用java程式碼列印楊輝三角形圖案

package yanghuisanjiaoxing; import java.util.Scanner; /*  * 使用二維陣列列印楊輝三角形的圖案  *   * 1  * 1 2 1  

Java連線MQ報錯,通道協商失敗 MQJE001: 完成程式碼為“2”,原因為“2059

我也曾經遇到過這個錯誤,當時佇列管理器,佇列,通道都一一建立,但就是報錯 HostName=192.168.8.46 Channel=CH1 QManager=WNMS3_QM MQJE001:

【死磕JVM】——-2Java程式碼編譯和執行的整個過程

Java程式碼編譯是由Java原始碼編譯器來完成的,流程圖如下: Java位元組碼的執行是由JVM執行引擎來完成的,流程圖如下: Java程式碼編譯和執行的整個過程包含以下三個重要機制: 1.Java程式碼編譯機制。 2.類載入機制。 3.類執行機制。 Java原始碼編

java程式碼書寫規範

一、目的     對於程式碼,首要要求是它必須正確,能夠按照程式設計師的真實思想去執行;第二個的要求是程式碼必須清晰易懂,使別的程式設計師能夠容易理解程式碼所進行的實際工作。在軟體工程領域,源程式的風格統一標誌著可維護性、可讀性,是軟體專案的一個重要組成部分。而目前還沒有成文