摘要:的動態性反射機制動態編譯動態執行代碼動態字節碼操作動態語言程序運行時可以改變程序得結構或變量類型典型語言等如下代碼不是動態語言但有一定的動態性我們可以利用反射機制字節碼操作獲得類似動態語言的特性的動態性讓編程的時候更加靈活反射機制反射機制指
1.Java的動態性
反射機制
動態編譯
動態執行JavaScript代碼
動態字節碼操作
2.動態語言程序運行時,可以改變程序得結構或變量類型.典型語言:
Python,Ruby,JavaScript等.
如下JavaScript代碼
function test(){ var s = "var a=3;var b=5;alert(a+b);"; eval(s); }
C,C++,Java不是動態語言,但Java有一定的動態性,我們可以利用反射機制,字節碼操作獲得類似動態語言的特性
Java的動態性讓編程的時候更加靈活
3.反射機制反射機制指的是可以在運行期間加載一些知道名字的類
對于任意一個已加載的類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能調用它的任意一個方法或屬性
Class c = Class.forName("com.test.User");
類加載完之后,在堆內存中會產生一個Class類的對象(一個類只有一個Class對象),這個對象包含了完整的類的結構信息,我們可以通過這個對象看到類的結果
4.Class類介紹java.lang.Class類十分特殊,用來表示java中類型(class/interface/enum/annotation/primitive type/void)本身
Class類的對象包含了某個被加載類的結構,一個被加載的類對應一個Class對象
當一個class被加載,或當加載器(class loader)的defineClass()被JVM調用,JVM便會自動產生一個Class對象
Class類是Reflection的根源
針對任何你想動態加載,運行的類,只有先獲得相應的Class對象
User bean:
package com.lorinda.bean; public class User { private int id; private int age; private String uname; public User(int id, int age, String uname) { super(); this.id = id; this.age = age; this.uname = uname; } public User() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getUname() { return uname; } public void setUname(String uname) { this.uname = uname; } }
Demo01 測試各種類型對應Class對象的獲取方式:
/** * 測試各種類型對應Class對象的獲取方式 * @author Matrix42 * */ public class ReflectionDemo01 { public static void main(String[] args) { String path = "com.lorinda.bean.User"; try { Class> clazz = Class.forName(path); System.out.println(clazz); //class com.lorinda.bean.User System.out.println(clazz.hashCode()); //366712642 //同樣的類只會被加載一次 Class> clazz2 = Class.forName(path); System.out.println(clazz2.hashCode()); //366712642 Class5.Class類的對象如何獲取?strClazz = String.class; //類名.class Class> strClazz2 = path.getClass(); //對象.getClass(); System.out.println(strClazz==strClazz2);//true Class> intClazz = int.class; int[] arr01 = new int[10]; int[] arr02 = new int [30]; int[][] arr03 = new int[30][3]; //數組的Class對象只與類型和維度有關 System.out.println(arr01.getClass()==arr02.getClass()); //true System.out.println(arr01.getClass().hashCode()); //1829164700 System.out.println(arr03.getClass().hashCode()); //2018699554 } catch (ClassNotFoundException e) { e.printStackTrace(); } }
對于對象可以使用getClass()
使用Class.forName() (最常使用)
使用.class
6.反射機制的常見作用動態加載類,動態獲取類的信息(屬性,方法,構造器)
動態構造對象
動態調用類和對象的任意方法,構造器
動態調用和處理屬性
獲取泛型信息
處理注解
Demo02 獲取方法,屬性,構造器等的信息:
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * 獲取方法,屬性,構造器等的信息 * @author Matrix42 * */ public class ReflectionDemo02 { public static void main(String[] args) { String path = "com.lorinda.bean.User"; try { Class> clazz = Class.forName(path); //獲取類的名字 System.out.println(clazz.getName());//獲得包名+類名:com.lorinda.bean.User System.out.println(clazz.getSimpleName());//獲得類名:User //獲取屬性信息 //Field[] fields = clazz.getFields();//只能獲取public的field Field[] fields = clazz.getDeclaredFields();//獲得所有的field Field field = clazz.getDeclaredField("uname");//根據名字獲取field for(Field temp:fields){ System.out.println("屬性: "+temp); } //獲取方法 Method[] methods = clazz.getDeclaredMethods(); Method method01 = clazz.getDeclaredMethod("getUname", null); //如果方法有參數,則必須傳遞參數類型對應的Class對象 Method method02 = clazz.getDeclaredMethod("setUname", String.class); for(Method m:methods){ System.out.println("方法: "+m); } //獲得構造器信息 Constructor[] constructors = clazz.getDeclaredConstructors(); //多帶帶獲取,無參 Constructor c1 = clazz.getDeclaredConstructor(null); System.out.println("構造器: "+c1); //多帶帶獲取,有參 Constructor c2 = clazz.getDeclaredConstructor(int.class,int.class,String.class); System.out.println("構造器: "+c2); for(Constructor c:constructors){ System.out.println("構造器: "+c); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } }
Demo03 通過反射動態操作構造器,方法,屬性
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import com.lorinda.bean.User; /** * 通過反射動態操作構造器,方法,屬性 * @auther Matrix42 */ public class ReflectionDemo03 { public static void main(String[] args) { String path = "com.lorinda.bean.User"; try { Class clazz = Class.forName(path); //動態操作構造器 User u = (User) clazz.newInstance(); //調用了User的無參構造方法 Constructor7.反射機制性能問題c = clazz.getConstructor(int.class,int.class,String.class); User u2 = c.newInstance(1000,20,"Matrix42"); System.out.println(u2.getUname()); //通過反射調用普通方法 //好處:方法名,參數都可以是變量,可以從數據庫讀取 User u3 = (User) clazz.newInstance(); Method method = clazz.getDeclaredMethod("setUname", String.class); method.invoke(u3, "Matrix42"); System.out.println(u3.getUname()); //通過反射操作屬性 User u4 = (User) clazz.newInstance(); Field f = clazz.getDeclaredField("uname"); f.setAccessible(true); f.set(u4, "24xirtaM"); //默認會報錯,添加f.setAccessible(true);關閉安全檢查 //can not access a member of class com.lorinda.bean.User with modifiers "private" System.out.println(u4.getUname()); //正常調用 System.out.println(f.get(u4)); //通過反射調用 } catch (Exception e) { e.printStackTrace(); } } }
當你獲得靈活性的時候也會犧牲你的性能
setAccessible
啟用和禁用安全檢查的開關,值為true則表示反射的對象在使用時應取消Java語言訪問檢查.值為fals則表示反射的對象應該實施Java語言訪問檢查.并不是為true就能訪問,為false就不能訪問
禁止安全檢查,可以提高反射的運行速度
可以考慮使用:cglib/javasssist字節碼操作
反射性能測試:
import java.lang.reflect.Method; import com.lorinda.bean.User; public class ReflectionDemo04 { public static void test01(){ User user = new User(); long startTime = System.currentTimeMillis(); for(int i=0;i<1000000000L;i++){ user.getUname(); } long endTime = System.currentTimeMillis(); //421ms System.out.println("普通方法調用,執行10億次,耗時:"+(endTime-startTime)+"ms"); } public static void test02() throws Exception{ User user = new User(); Class clazz = user.getClass(); Method m = clazz.getDeclaredMethod("getUname", null); long startTime = System.currentTimeMillis(); for(int i=0;i<1000000000L;i++){ m.invoke(user, null); } long endTime = System.currentTimeMillis(); //1650ms System.out.println("反射動態調用,執行10億次,耗時:"+(endTime-startTime)+"ms"); } public static void test03() throws Exception{ User user = new User(); Class clazz = user.getClass(); Method m = clazz.getDeclaredMethod("getUname", null); m.setAccessible(true); long startTime = System.currentTimeMillis(); for(int i=0;i<1000000000L;i++){ m.invoke(user, null); } long endTime = System.currentTimeMillis(); //1153ms System.out.println("反射動態調用,跳過安全檢查,執行10億次,耗時:"+(endTime-startTime)+"ms"); } public static void main(String[] args) throws Exception { test01(); test02(); test03(); } }
可以看出在java8中使用安全檢查的反射耗時大約是普通調用的4倍,不使用安全檢查是普通調用的2.5倍
8.反射操作泛型(Generic)Java采用泛型擦除機制來引入泛型.Java中泛型僅僅是給編譯器javac使用的,確保數據的安全性和免去強制類型轉換的麻煩.但是,一旦編譯完成,所有和泛型有關的類型全部擦除.
為了通過反射操作這些類型以迎合實際開發的需要,Java就新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType幾種類型來代表不能被歸一到Class類中的類型但是又和原始類型齊名的類型.
ParameterizedType:表示一種參數化類型,比如Collection
GenericArrayType:表示一種元素類型是參數化類型或者類型變量的數組類型
TypeVariable:是各種類型變量的公共父接口
WildcardType:表示一種通配符類型表達式,比如?,? extends Number,? super Integer [wildcard就是通配符的意思]
Demo05 通過反射讀取泛型
import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map; import com.lorinda.bean.User; /** * 通過反射讀取泛型 * @author Matrix42 * */ public class ReflectionDemo05 { public void test01(Map9.反射操作注解map,List list){ System.out.println("ReflectionDemo05.test02"); } public Map test02(){ System.out.println("ReflectionDemo05.test2"); return null; } public static void main(String[] args) { try { //獲取指定方法參數泛型信息 Method m = ReflectionDemo05.class.getMethod("test01", Map.class,List.class); Type[] t = m.getGenericParameterTypes(); for(Type paramType:t){ System.out.println("#"+paramType); if(paramType instanceof ParameterizedType){ Type[] genericTypes = ((ParameterizedType)paramType).getActualTypeArguments(); for(Type genericType:genericTypes){ System.out.println("泛型類型: "+genericType); } } } /* #java.util.Map 泛型類型: class java.lang.String 泛型類型: class com.lorinda.bean.User #java.util.List 泛型類型: class com.lorinda.bean.User */ //獲得指定方法返回值泛型信息 Method m2 = ReflectionDemo05.class.getMethod("test02", null); Type returnType = m2.getGenericReturnType(); if(returnType instanceof ParameterizedType){ Type[] genericTypes = ((ParameterizedType)returnType).getActualTypeArguments(); for(Type genericType:genericTypes){ System.out.println("返回值,泛型類型: "+genericType); } } /* 返回值,泛型類型: class java.lang.Integer 返回值,泛型類型: class com.lorinda.bean.User */ } catch (Exception e) { e.printStackTrace(); } } }
Student類:
package com.lorinda.bean; import com.demo.util.MField; import com.demo.util.MTable; @MTable("tb_student") public class MStudent { @MField(columnName="id",type="int",length=10) private int id; @MField(columnName="sname",type="varchar",length=10) private String studentName; @MField(columnName="age",type="int",length=3) private int age; public MStudent(int id, String studentName, int age) { super(); this.id = id; this.studentName = studentName; this.age = age; } public MStudent() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getStudentName() { return studentName; } public void setStudentName(String studentName) { this.studentName = studentName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
Table注解:
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(value={ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface MTable { String value(); }
Field注解:
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(value={ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface MField { String columnName(); String type(); int length(); }
Demo06 通過反射讀取注解
import java.lang.annotation.Annotation; import java.lang.reflect.Field; public class ReflectionDemo06 { public static void main(String[] args) { try { Class clazz = Class.forName("com.lorinda.bean.MStudent"); //獲得類的所有有效注解 Annotation[] annotations = clazz.getAnnotations(); for(Annotation a:annotations){ System.out.println(a); } //獲得類的指定注解 MTable table = (MTable) clazz.getAnnotation(MTable.class); System.out.println(table.value()); //獲得類的屬性的注解 Field f = clazz.getDeclaredField("studentName"); MField field = f.getAnnotation(MField.class); System.out.println(field.columnName()+"--"+field.type()+"--"+field.length()); //可以根據獲得的表名,字段的信息,拼出DDL語句,然后使用JDBC執行這個SQL,在數據庫中生成相關的表 } catch (Exception e) { e.printStackTrace(); } } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/71949.html
近期在維護公司項目的時候遇到一個問題,因為實體類中的 set 方法涉及到了業務邏輯,因此在給對象賦值的過程中不能夠使用 set 方法,為了實現功能,所以采用了反射的機制給對象屬性賦值,借此機會也了解了反射的一些具體用法和使用場景,分以下兩點對反射進行分析: 反射的優勢和劣勢 反射的應用場景 反射的優勢和劣勢 ??個人理解,反射機制實際上就是上帝模式,如果說方法的調用是 Java 正確的打開方式...
摘要:反射機制是什么反射機制是在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法對于任意一個對象,都能夠調用它的任意一個方法和屬性這種動態獲取的信息以及動態調用對象的方法的功能稱為語言的反射機制反射機制能做什么反射機制主要提供了以下功 反射機制是什么 反射機制是在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意一個方法和屬性;這種...
摘要:效率運行效率使用反射減低程序的運行效率。開發效率由于反射運用到各個框架中,大大加快了開發的效率。 反射的核心就是Class對象,每一個類被jvm加載都會有一個對應的class對象,這個class對象包含了這個類的結構信息,反射就是會通過反射api反復操作這個class對象(屬性,方法,注解,構造器,泛型),但是反射會降低程序的運行效率,比普通方法要慢30倍,通過setAccessble...
摘要:一反射機制概念程序運行時,允許改變程序結構或變量類型,這種語言稱為動態語言,如,是動態語言顯然,,不是動態語言,但是有著一個非常突出的動態相關機制。相關的為二獲取源頭重點打開權限所有類的對象其實都是的實例。 一、Java反射機制概念 程序運行時,允許改變程序結構或變量類型,這種語言稱為動態語言,如Python, Ruby是動態語言;顯然C++,Java,C#不是動態語言,但是JAVA有...
摘要:與都繼承自類,在中也是使用字符數組保存字符串,,這兩種對象都是可變的。采用字節碼的好處語言通過字節碼的方式,在一定程度上解決了傳統解釋型語言執行效率低的問題,同時又保留了解釋型語言可移植的特點。 String和StringBuffer、StringBuilder的區別是什么?String為什么是不可變的? String和StringBuffer、StringBuilder的區別 可變性...
閱讀 3027·2023-04-25 18:06
閱讀 3272·2021-11-22 09:34
閱讀 2857·2021-08-12 13:30
閱讀 2045·2019-08-30 15:44
閱讀 1661·2019-08-30 13:09
閱讀 1630·2019-08-30 12:45
閱讀 1715·2019-08-29 11:13
閱讀 3608·2019-08-28 17:51