反射圖示:
簡單上代碼了解一下:
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:文章待完善,如存在不正之處歡迎大佬指出。