java-java動態性之反射,動態編譯,動態執行js及動態字節碼操作


反射圖示:

簡單上代碼了解一下:

1.實體類

 1 package com.reflection;
 2 
 3 public class Student {
 4     //學生實體類,包含編號,名字,所屬班級的屬性
 5     private int id;
 6     private String name;
 7     private String cname;
 8 
 9     public Student() {
10         super();
11     }
12     //構造器
13     public Student(int id, String name, String cname) {
14         super();
15         this.id = id;
16         this.name = name;
17         this.cname = cname;
18     }
19 
20     public int getId() {
21         return id;
22     }
23     public void setId(int id) {
24         this.id = id;
25     }
26 
27     public String getName() {
28         return name;
29     }
30     public void setName(String name) {
31         this.name = name;
32     }
33     
34     public String getCname() {
35         return cname;
36     }
37     public void setCname(String cname) {
38         this.cname = cname;
39     }
40     
41 }

2.方法示例:

  1 package com.reflection;
  2 
  3 import java.lang.reflect.Constructor;
  4 import java.lang.reflect.Field;
  5 import java.lang.reflect.InvocationTargetException;
  6 import java.lang.reflect.Method;
  7 import java.lang.reflect.ParameterizedType;
  8 import java.lang.reflect.Type;
  9 import java.util.ArrayList;
 10 import java.util.List;
 11 
 12 import javax.script.ScriptEngine;
 13 import javax.script.ScriptEngineManager;
 14 import javax.script.ScriptException;
 15 import javax.tools.JavaCompiler;
 16 import javax.tools.ToolProvider;
 17 
 18 import com.sun.javafx.collections.MappingChange.Map;
 19 
 20 /*
 21  * Java動態性:
 22  * 動態語言:
 23  * 程序運行時,可以改變程序結構或變量類型,Java並非動態語言,但其擁有動態性,利用反射機制以及字節碼操作獲得類似動態語言的特性.
 24  * 一.反射機制:可以於運行時加載,探知,使用編譯期間完全未知的類。 
 25  *  (1)PS:程序在運行狀態中,可以動態的加載一個只有名稱的類,對於任意一個已加載的類,都能夠知道這個類的所有屬性和方法,對於任意一個對象,都能夠調用它的任意一個方法和屬性
 26  *  (2)操作方式:Class c=Class.forName("com.reflection.Reflect");
 27  *  (3)反射:加載完類之后,在堆內存中會產生一個Class類型的對象(一個類只有一個Class對象),該對象包含了完整的類的結構信息,通過這個對象可以看到類的結構,這便是反射。
 28  *  (4)Class類是Reflection的根源:針對任何想要動態加載,運行的類,唯有先獲得相應的Class對象。
 29  *  (5)獲取Class對象的三種方式: getClass(),Class.forName(),.class語法
 30  *  (6)反射機制的常見作用:
 31  *  動態加載類,動態獲取類的信息(屬性,方法,構造器)/動態構造對象/動態調用類和對象的任意方法及構造器/
 32  *  動態調用和處理屬性/獲取泛型信息/處理注解
 33  *  (7)反射機制的性能問題:
 34  *  利用反射執行類方法執行速度大概為類普通方法執行速度的1/30,也就是很慢,效率低,加上setAccessible()后可提高效率
 35  *  setAccessible():啟用和禁用訪問安全檢查的開關,值為true,則表示取消訪問安全檢查,反之
 36  * 
 37  * 二.動態編譯:
 38  * 動態編譯的兩種做法:
 39  * (1)通過Runtime調用javac,啟動新的進程去操作
 40  * ->Runtime run=Runtime.getRuntime();
 41  *   Process process=run.exec("java -cp +類文件絕對路徑");
 42  * (2)通過JavaCompiler動態編譯
 43  * ->JavaCompiler compiler=ToolProvider.getSystemJavaCompiler();
 44  *   int result=compiler.run(null,null,null,sourceFile);
 45  *   第一個參數:為java編譯器提供參數  InputStream
 46  *   第二個參數:得到java編譯器的輸出信息 OutputStream
 47  *   第三個參數:接收編譯器的錯誤信息  
 48  *   第四個參數:可變參數(為String數組)能傳入一個或多個java源文件
 49  *   返回值:1表示編譯成功,0表示編譯失敗
 50  * 
 51  * 三.動態執行JavaScript代碼:
 52  * Java腳本引擎:
 53  *  使得java的應用程序可以通過一套固定的接口與各種腳本引擎交互,從而達到在Java平台上調用各種腳本語言的目的。
 54  *  可以把一些復雜異變的業務邏輯交給腳本語言處理,大大提高開發效率
 55  *  (1)獲得腳本引擎對象:
 56  *  ScriptEngineManager sem=new ScriptEngineManager();
 57  *  ScriptEngine engine=sem.getEngineByName("javascript");
 58  *  功能:
 59  * (1)獲取腳本程序輸入,通過腳本引擎運行腳本並返回運行結果,這是最核心的接口。 JS使用了Rhino
 60  * (2)通過腳本引擎的運行上下文在腳本和Java平台間交換數據。
 61  * (3)通過Java應用程序調用腳本函數。
 62  *  
 63  * 四.動態字節碼操作:
 64  * 功能:動態生成新的類,動態改變某個類的結構(增加,刪除,修改 新的屬性/方法 )
 65  * 優勢:比反射的開銷小,性能高,Javassist性能高於反射,低於ASM
 66  * 常見的字節碼操作類庫:
 67  * BCEL:在實際的JVM指令層次上進行操作,擁有豐富的JVM指令級支持
 68  * ASM:是一個輕量級java字節碼操作框架,直接涉及到JVM底層的操作和指令
 69  * CGLIB:是一個強大的,高性能,高質量的code生成類庫,基於ASM實現
 70  * Javassist:是一個開源的分析,編輯和創建字節碼的類庫,性能較ASM差,較cglib差不多,使用簡單
 71  * ->最外層的API和JAVA反射包中的API頗為相似:
 72  * 主要由CtClass,CtMethod以及CtField幾個類組成,
 73  * 用以執行和JDK反射API中java.lang.Class,java.lang.reflect.Method
 74  * 以及java.lang.reflect.Method.Field相同的操作
 75  * 
 76  * 局限性:
 77  * 不支持泛型,枚舉,不支持注釋修改,但可以通過底層的javassist類解決
 78  * 不支持數組的初始化,內部類和匿名類,不支持continue,break語句還有部分繼承關系
 79  * 
 80  */
 81 
 82 @SuppressWarnings("all")
 83 public class Reflect {
 84 
 85     public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, ScriptException {
 86 
 87         try {
 88             getInfoByReflect();
 89             useConstructorByReflect();
 90             useReflectMethod();
 91             getTypeAll();
 92             /*testComplier();*/
 93             scriptEngine();
 94         } catch (ClassNotFoundException e) {
 95             e.printStackTrace();
 96         }
 97 
 98     }
 99 
100     //通過反射獲取Class對象里面對應類的屬性
101     public static void getInfoByReflect() throws ClassNotFoundException {
102         //獲取Student類的Class對象
103         Class c=Class.forName("com.reflection.Student");
104         //通過該Class對象獲取該類的具體名字(包含包名)及類名
105         String realName=c.getName();
106         String name=c.getSimpleName();
107         System.out.println("具體名字:"+realName+" 類名:"+name);
108 
109         //獲取類的屬性
110         //Field[] field=c.getFields();//只能獲取public的屬性
111         Field[] fields=c.getDeclaredFields();
112         //獲取所有屬性
113         for(Field f:fields) {
114             System.out.println("屬性:"+f);
115         }
116         /*獲取類所有的方法
117         PS:如果方法有參,則必須參數類型對應的Class對象
118         Method m1=c.getDeclaredMethod("getName", null);
119         Method m2=c.getDeclaredMethod("setName", String.class);*/
120         Method[] methods=c.getMethods();
121         for(Method m:methods) {
122             System.out.println("方法:"+m);
123         }
124         //獲取類所有的構造器
125         Constructor[] constructors=    c.getConstructors();
126         for(Constructor con:constructors) {
127             System.out.println("構造器:"+con);
128         }
129     }
130 
131     //通過反射調用構造方法,構造對象,創建記錄並將其放入集合中,然后打印出來
132     public static void useConstructorByReflect() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
133         Class c=Class.forName("com.reflection.Student");
134         Constructor<Student> cr=c.getConstructor(int.class,String.class,String.class);
135         Student s1=cr.newInstance(123,"張三","軟件一班");
136         Student s2=cr.newInstance(456,"李四","軟件二班");
137         List<Student> list=new ArrayList<Student>();
138         list.add(s1);
139         list.add(s2);
140         System.out.println("編號:"+list.get(0).getId()+" 姓名:"+list.get(0).getName()+" 班級:"+list.get(0).getCname());
141         System.out.println("編號:"+list.get(1).getId()+" 姓名:"+list.get(1).getName()+" 班級:"+list.get(1).getCname());
142     }
143 
144     //利用對象里面的方法來對 Student實體類進行初始化數據操作
145     public static void useReflectMethod() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
146         Class c2=Class.forName("com.reflection.Student");
147         Student s3=(Student)c2.newInstance();
148         //先獲取Class對象里面的方法
149         Method m2=c2.getDeclaredMethod("setName", String.class);
150         //使用該方法
151         m2.invoke(s3, "王五");
152         System.out.println("方法實現后獲取值為:"+s3.getName());
153     }
154 
155     //對包含泛型的方法進行處理
156     public static void getTypeAll() throws NoSuchMethodException, SecurityException {
157         //獲取指定方法泛型參數信息
158         Method m3=Reflect.class.getMethod("test01",Map.class,List.class);
159         Type[] types=m3.getGenericParameterTypes();
160         for(Type t:types) {
161             System.out.println("#"+t);
162             if (t instanceof ParameterizedType) {
163                 Type[] generalType=((ParameterizedType) t).getActualTypeArguments();
164                 for(Type gtype:generalType) {
165                     System.out.println("泛型類型為:"+gtype);
166                 }
167             }
168         }
169         //獲取指定方法泛型返回值信息
170         Method m4=Reflect.class.getMethod("test02", null);
171         Type returnType=m4.getGenericReturnType();
172         if(returnType instanceof ParameterizedType) {
173             Type[] generalType=((ParameterizedType) returnType).getActualTypeArguments();
174             for(Type gtype:generalType) {
175                 System.out.println("返回值泛型類型為:"+gtype);
176             }
177         }
178     }
179 
180     //動態編譯方法實現
181     public static void testComplier() {
182         JavaCompiler compiler=ToolProvider.getSystemJavaCompiler();
183         int result=compiler.run(null,null,null,"");
184         System.out.println(result==0?"編譯成功":"編譯失敗");
185     }
186 
187     //構造一個帶泛型參數的方法
188     public void test01(Map<String,Student> map,List<Student> stu){
189         System.out.println("測試");
190     }
191     //構造一個帶泛型返回值的方法
192     public Map<String,Student> test02(){
193         return null;
194     }
195 
196     //腳本引擎簡單使用
197     public static void scriptEngine() throws ScriptException {
198         //獲取腳本引擎對象
199         ScriptEngineManager sem=new ScriptEngineManager();
200         ScriptEngine engine=sem.getEngineByName("javascript");
201         //定義變量存儲到腳本引擎的上下文中
202         engine.put("msg", "我很喜歡敲代碼!");
203         System.out.println("獲取到的信息為:"+engine.get("msg"));
204 
205         String str="var user= {name:'張三',age:18};";
206         str +="print('用戶名:'+user.name);";
207         //執行腳本
208         engine.eval(str);
209         //利用腳本引擎執行javascript的函數
210         String st="function time() { var a=10,b=a*10;print('最終結果為:'+b);}; time();";
211         engine.eval(st);           
212     }
213 }

效果截圖:

 

ps:文章待完善,如存在不正之處歡迎大佬指出。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM