摘要:的動(dòng)態(tài)性反射機(jī)制動(dòng)態(tài)編譯動(dòng)態(tài)執(zhí)行代碼動(dòng)態(tài)字節(jié)碼操作動(dòng)態(tài)語言程序運(yùn)行時(shí)可以改變程序得結(jié)構(gòu)或變量類型典型語言等如下代碼不是動(dòng)態(tài)語言但有一定的動(dòng)態(tài)性我們可以利用反射機(jī)制字節(jié)碼操作獲得類似動(dòng)態(tài)語言的特性的動(dòng)態(tài)性讓編程的時(shí)候更加靈活反射機(jī)制反射機(jī)制指
1.Java的動(dòng)態(tài)性
反射機(jī)制
動(dòng)態(tài)編譯
動(dòng)態(tài)執(zhí)行JavaScript代碼
動(dòng)態(tài)字節(jié)碼操作
2.動(dòng)態(tài)語言程序運(yùn)行時(shí),可以改變程序得結(jié)構(gòu)或變量類型.典型語言:
Python,Ruby,JavaScript等.
如下JavaScript代碼
function test(){ var s = "var a=3;var b=5;alert(a+b);"; eval(s); }
C,C++,Java不是動(dòng)態(tài)語言,但Java有一定的動(dòng)態(tài)性,我們可以利用反射機(jī)制,字節(jié)碼操作獲得類似動(dòng)態(tài)語言的特性
Java的動(dòng)態(tài)性讓編程的時(shí)候更加靈活
3.反射機(jī)制反射機(jī)制指的是可以在運(yùn)行期間加載一些知道名字的類
對于任意一個(gè)已加載的類,都能夠知道這個(gè)類的所有屬性和方法;對于任意一個(gè)對象,都能調(diào)用它的任意一個(gè)方法或?qū)傩?/p>
Class c = Class.forName("com.test.User");
類加載完之后,在堆內(nèi)存中會產(chǎn)生一個(gè)Class類的對象(一個(gè)類只有一個(gè)Class對象),這個(gè)對象包含了完整的類的結(jié)構(gòu)信息,我們可以通過這個(gè)對象看到類的結(jié)果
4.Class類介紹java.lang.Class類十分特殊,用來表示java中類型(class/interface/enum/annotation/primitive type/void)本身
Class類的對象包含了某個(gè)被加載類的結(jié)構(gòu),一個(gè)被加載的類對應(yīng)一個(gè)Class對象
當(dāng)一個(gè)class被加載,或當(dāng)加載器(class loader)的defineClass()被JVM調(diào)用,JVM便會自動(dòng)產(chǎn)生一個(gè)Class對象
Class類是Reflection的根源
針對任何你想動(dòng)態(tài)加載,運(yùn)行的類,只有先獲得相應(yīng)的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 測試各種類型對應(yīng)Class對象的獲取方式:
/** * 測試各種類型對應(yīng)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]; //數(shù)組的Class對象只與類型和維度有關(guān) 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.反射機(jī)制的常見作用動(dòng)態(tài)加載類,動(dòng)態(tài)獲取類的信息(屬性,方法,構(gòu)造器)
動(dòng)態(tài)構(gòu)造對象
動(dòng)態(tài)調(diào)用類和對象的任意方法,構(gòu)造器
動(dòng)態(tài)調(diào)用和處理屬性
獲取泛型信息
處理注解
Demo02 獲取方法,屬性,構(gòu)造器等的信息:
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * 獲取方法,屬性,構(gòu)造器等的信息 * @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");//根據(jù)名字獲取field for(Field temp:fields){ System.out.println("屬性: "+temp); } //獲取方法 Method[] methods = clazz.getDeclaredMethods(); Method method01 = clazz.getDeclaredMethod("getUname", null); //如果方法有參數(shù),則必須傳遞參數(shù)類型對應(yīng)的Class對象 Method method02 = clazz.getDeclaredMethod("setUname", String.class); for(Method m:methods){ System.out.println("方法: "+m); } //獲得構(gòu)造器信息 Constructor[] constructors = clazz.getDeclaredConstructors(); //多帶帶獲取,無參 Constructor c1 = clazz.getDeclaredConstructor(null); System.out.println("構(gòu)造器: "+c1); //多帶帶獲取,有參 Constructor c2 = clazz.getDeclaredConstructor(int.class,int.class,String.class); System.out.println("構(gòu)造器: "+c2); for(Constructor c:constructors){ System.out.println("構(gòu)造器: "+c); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } }
Demo03 通過反射動(dòng)態(tài)操作構(gòu)造器,方法,屬性
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import com.lorinda.bean.User; /** * 通過反射動(dòng)態(tài)操作構(gòu)造器,方法,屬性 * @auther Matrix42 */ public class ReflectionDemo03 { public static void main(String[] args) { String path = "com.lorinda.bean.User"; try { Class clazz = Class.forName(path); //動(dòng)態(tài)操作構(gòu)造器 User u = (User) clazz.newInstance(); //調(diào)用了User的無參構(gòu)造方法 Constructor7.反射機(jī)制性能問題c = clazz.getConstructor(int.class,int.class,String.class); User u2 = c.newInstance(1000,20,"Matrix42"); System.out.println(u2.getUname()); //通過反射調(diào)用普通方法 //好處:方法名,參數(shù)都可以是變量,可以從數(shù)據(jù)庫讀取 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"); //默認(rèn)會報(bào)錯(cuò),添加f.setAccessible(true);關(guān)閉安全檢查 //can not access a member of class com.lorinda.bean.User with modifiers "private" System.out.println(u4.getUname()); //正常調(diào)用 System.out.println(f.get(u4)); //通過反射調(diào)用 } catch (Exception e) { e.printStackTrace(); } } }
當(dāng)你獲得靈活性的時(shí)候也會犧牲你的性能
setAccessible
啟用和禁用安全檢查的開關(guān),值為true則表示反射的對象在使用時(shí)應(yīng)取消Java語言訪問檢查.值為fals則表示反射的對象應(yīng)該實(shí)施Java語言訪問檢查.并不是為true就能訪問,為false就不能訪問
禁止安全檢查,可以提高反射的運(yùn)行速度
可以考慮使用:cglib/javasssist字節(jié)碼操作
反射性能測試:
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("普通方法調(diào)用,執(zhí)行10億次,耗時(shí):"+(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("反射動(dòng)態(tài)調(diào)用,執(zhí)行10億次,耗時(shí):"+(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("反射動(dòng)態(tài)調(diào)用,跳過安全檢查,執(zhí)行10億次,耗時(shí):"+(endTime-startTime)+"ms"); } public static void main(String[] args) throws Exception { test01(); test02(); test03(); } }
可以看出在java8中使用安全檢查的反射耗時(shí)大約是普通調(diào)用的4倍,不使用安全檢查是普通調(diào)用的2.5倍
8.反射操作泛型(Generic)Java采用泛型擦除機(jī)制來引入泛型.Java中泛型僅僅是給編譯器javac使用的,確保數(shù)據(jù)的安全性和免去強(qiáng)制類型轉(zhuǎn)換的麻煩.但是,一旦編譯完成,所有和泛型有關(guān)的類型全部擦除.
為了通過反射操作這些類型以迎合實(shí)際開發(fā)的需要,Java就新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType幾種類型來代表不能被歸一到Class類中的類型但是又和原始類型齊名的類型.
ParameterizedType:表示一種參數(shù)化類型,比如Collection
GenericArrayType:表示一種元素類型是參數(shù)化類型或者類型變量的數(shù)組類型
TypeVariable:是各種類型變量的公共父接口
WildcardType:表示一種通配符類型表達(dá)式,比如?,? 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 { //獲取指定方法參數(shù)泛型信息 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()); //可以根據(jù)獲得的表名,字段的信息,拼出DDL語句,然后使用JDBC執(zhí)行這個(gè)SQL,在數(shù)據(jù)庫中生成相關(guān)的表 } catch (Exception e) { e.printStackTrace(); } } }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/71949.html
近期在維護(hù)公司項(xiàng)目的時(shí)候遇到一個(gè)問題,因?yàn)閷?shí)體類中的 set 方法涉及到了業(yè)務(wù)邏輯,因此在給對象賦值的過程中不能夠使用 set 方法,為了實(shí)現(xiàn)功能,所以采用了反射的機(jī)制給對象屬性賦值,借此機(jī)會也了解了反射的一些具體用法和使用場景,分以下兩點(diǎn)對反射進(jìn)行分析: 反射的優(yōu)勢和劣勢 反射的應(yīng)用場景 反射的優(yōu)勢和劣勢 ??個(gè)人理解,反射機(jī)制實(shí)際上就是上帝模式,如果說方法的調(diào)用是 Java 正確的打開方式...
摘要:反射機(jī)制是什么反射機(jī)制是在運(yùn)行狀態(tài)中,對于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法對于任意一個(gè)對象,都能夠調(diào)用它的任意一個(gè)方法和屬性這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對象的方法的功能稱為語言的反射機(jī)制反射機(jī)制能做什么反射機(jī)制主要提供了以下功 反射機(jī)制是什么 反射機(jī)制是在運(yùn)行狀態(tài)中,對于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法;對于任意一個(gè)對象,都能夠調(diào)用它的任意一個(gè)方法和屬性;這種...
摘要:效率運(yùn)行效率使用反射減低程序的運(yùn)行效率。開發(fā)效率由于反射運(yùn)用到各個(gè)框架中,大大加快了開發(fā)的效率。 反射的核心就是Class對象,每一個(gè)類被jvm加載都會有一個(gè)對應(yīng)的class對象,這個(gè)class對象包含了這個(gè)類的結(jié)構(gòu)信息,反射就是會通過反射api反復(fù)操作這個(gè)class對象(屬性,方法,注解,構(gòu)造器,泛型),但是反射會降低程序的運(yùn)行效率,比普通方法要慢30倍,通過setAccessble...
摘要:一反射機(jī)制概念程序運(yùn)行時(shí),允許改變程序結(jié)構(gòu)或變量類型,這種語言稱為動(dòng)態(tài)語言,如,是動(dòng)態(tài)語言顯然,,不是動(dòng)態(tài)語言,但是有著一個(gè)非常突出的動(dòng)態(tài)相關(guān)機(jī)制。相關(guān)的為二獲取源頭重點(diǎn)打開權(quán)限所有類的對象其實(shí)都是的實(shí)例。 一、Java反射機(jī)制概念 程序運(yùn)行時(shí),允許改變程序結(jié)構(gòu)或變量類型,這種語言稱為動(dòng)態(tài)語言,如Python, Ruby是動(dòng)態(tài)語言;顯然C++,Java,C#不是動(dòng)態(tài)語言,但是JAVA有...
摘要:與都繼承自類,在中也是使用字符數(shù)組保存字符串,,這兩種對象都是可變的。采用字節(jié)碼的好處語言通過字節(jié)碼的方式,在一定程度上解決了傳統(tǒng)解釋型語言執(zhí)行效率低的問題,同時(shí)又保留了解釋型語言可移植的特點(diǎn)。 String和StringBuffer、StringBuilder的區(qū)別是什么?String為什么是不可變的? String和StringBuffer、StringBuilder的區(qū)別 可變性...
閱讀 3057·2023-04-25 18:06
閱讀 3367·2021-11-22 09:34
閱讀 2890·2021-08-12 13:30
閱讀 2080·2019-08-30 15:44
閱讀 1698·2019-08-30 13:09
閱讀 1657·2019-08-30 12:45
閱讀 1744·2019-08-29 11:13
閱讀 3637·2019-08-28 17:51