Java反射机制概念及应用场景
Java反射機制概念及應用場景
Java的反射機制相信大家在平時的業務開發過程中應該很少使用到,但是在一些基礎框架的搭建上應用非常廣泛,今天簡單的總結學習一下。
1. 什么是反射機制?
Java反射機制是在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意一個方法;這種動態獲取的以及動態調用對象的方法的功能稱為Java的反射機制。
通俗理解:通過反射,任何類對我們來說都是透明的,想要獲取任何東西都可以,破壞程序安全性?
先來看看反射機制都提供了哪些功能。
2. 反射機制能夠獲取哪些信息?
在運行時判定任意一個對象所屬的類;
在運行時構造任意一個類的對象;
在運行時判定任意一個類所具有的成員變量和方法;
在運行時調用任意一個對象的方法;
生成動態代理;
主要的反射機制類:
java.lang.Class;?//類???????????????java.lang.reflect.Constructor;//構造方法?
java.lang.reflect.Field;?//類的成員變量???????
java.lang.reflect.Method;//類的方法
java.lang.reflect.Modifier;//訪問權限
2.1 class對象的獲取
//第一種方式?通過對象getClass方法Person?person?=?new?Person();
Class<?>?class1?=?person.getClass();
//第二種方式?通過類的class屬性
class1?=?Person.class;
try?{
????//第三種方式?通過Class類的靜態方法——forName()來實現
????class1?=?Class.forName("club.sscai.Person");
}?catch?(ClassNotFoundException?e)?{
????e.printStackTrace();
}
上邊這三種方式,最常用的是第三種,前兩種獲取 class 的方式沒有什么意義,畢竟你都導了包了。
2.2 獲取class對象的屬性、方法、構造函數等
Field[]?allFields?=?class1.getDeclaredFields();//獲取class對象的所有屬性Field[]?publicFields?=?class1.getFields();//獲取class對象的public屬性
try?{
????Field?ageField?=?class1.getDeclaredField("age");//獲取class指定屬性
????Field?desField?=?class1.getField("des");//獲取class指定的public屬性
}?catch?(NoSuchFieldException?e)?{
????e.printStackTrace();
}
Method[]?methods?=?class1.getDeclaredMethods();//獲取class對象的所有聲明方法
Method[]?allMethods?=?class1.getMethods();//獲取class對象的所有方法?包括父類的方法
Class?parentClass?=?class1.getSuperclass();//獲取class對象的父類
Class<?>[]?interfaceClasses?=?class1.getInterfaces();//獲取class對象的所有接口
Constructor<?>[]?allConstructors?=?class1.getDeclaredConstructors();//獲取class對象的所有聲明構造函數
Constructor<?>[]?publicConstructors?=?class1.getConstructors();//獲取class對象public構造函數
try?{
????Constructor<?>?constructor?=?class1.getDeclaredConstructor(new?Class[]{String.class});//獲取指定聲明構造函數
????Constructor?publicConstructor?=?class1.getConstructor(new?Class[]{});//獲取指定聲明的public構造函數
}?catch?(NoSuchMethodException?e)?{
????e.printStackTrace();
}
Annotation[]?annotations?=?class1.getAnnotations();//獲取class對象的所有注解
Annotation?annotation?=?class1.getAnnotation(Deprecated.class);//獲取class對象指定注解
Type?genericSuperclass?=?class1.getGenericSuperclass();//獲取class對象的直接超類的?Type
Type[]?interfaceTypes?=?class1.getGenericInterfaces();//獲取class對象的所有接口的type集合
2.3 反射機制獲取泛型類型
示例:
//People類public?class?People<T>?{}//Person類繼承People類public?class?Person<T>?extends?People<String>?implements?PersonInterface<Integer>?{}
//PersonInterface接口public?interface?PersonInterface<T>?{}
獲取泛型類型:
Person<String>?person?=?new?Person<>();//第一種方式?通過對象getClass方法
Class<?>?class1?=?person.getClass();
Type?genericSuperclass?=?class1.getGenericSuperclass();//獲取class對象的直接超類的?Type
Type[]?interfaceTypes?=?class1.getGenericInterfaces();//獲取class對象的所有接口的Type集合
getComponentType(genericSuperclass);
getComponentType(interfaceTypes[0]);
getComponentType具體實現
private?Class<?>?getComponentType(Type?type)?{Class<?>?componentType?=?null;
if?(type?instanceof?ParameterizedType)?{
????//getActualTypeArguments()返回表示此類型實際類型參數的?Type?對象的數組。
????Type[]?actualTypeArguments?=?((ParameterizedType)?type).getActualTypeArguments();
????if?(actualTypeArguments?!=?null?&&?actualTypeArguments.length?>?0)?{
????componentType?=?(Class<?>)?actualTypeArguments[0];
????}
}?else?if?(type?instanceof?GenericArrayType)?{
????//?表示一種元素類型是參數化類型或者類型變量的數組類型
????componentType?=?(Class<?>)?((GenericArrayType)?type).getGenericComponentType();
}?else?{
????componentType?=?(Class<?>)?type;
}
return?componentType;
}
2.4 通過反射機制獲取注解信息(知識點)
這種場景,經常在 Aop 使用,這里重點以獲取Method的注解信息為例。
try?{????//首先需要獲得與該方法對應的Method對象
????Method?method?=?class1.getDeclaredMethod("jumpToGoodsDetail",?new?Class[]{String.class,?String.class});
????Annotation[]?annotations1?=?method.getAnnotations();//獲取所有的方法注解信息
????Annotation?annotation1?=?method.getAnnotation(RouterUri.class);//獲取指定的注解信息
????TypeVariable[]?typeVariables1?=?method.getTypeParameters();
????Annotation[][]?parameterAnnotationsArray?=?method.getParameterAnnotations();//拿到所有參數注解信息
????Class<?>[]?parameterTypes?=?method.getParameterTypes();//獲取所有參數class類型
????Type[]?genericParameterTypes?=?method.getGenericParameterTypes();//獲取所有參數的type類型
????Class<?>?returnType?=?method.getReturnType();//獲取方法的返回類型
????int?modifiers?=?method.getModifiers();//獲取方法的訪問權限
}?catch?(NoSuchMethodException?e)?{
????e.printStackTrace();
}
3. 反射機制的應用實例
大家是不是經常遇到一種情況,比如兩個對象,Member 和 MemberView,很多時候我們都有可能進行相互轉換,那么我們常用的方法就是,把其中一個中的值挨個 get 出來,然后再挨個 set 到另一個中去,接下來我介紹的這種方法就可以解決這種問題造成的困擾:
public?class?TestClass{????public?double?eachOrtherToAdd(Integer?one,Double?two,Integer?three){
????????return?one?+?two?+?three;
????}
}
public?class?ReflectionDemo{
????public?static?void?main(String?args[]){
????????String?className?=?"initLoadDemo.TestClass";
????????String?methodName?=?"eachOrtherToAdd";
????????String[]?paramTypes?=?new?String[]{"Integer","Double","int"};
????????String[]?paramValues?=?new?String[]{"1","4.3321","5"};
????????//?動態加載對象并執行方法
????????initLoadClass(className,?methodName,?paramTypes,?paramValues);
????}
????("rawtypes")
????private?static?void?initLoadClass(String?className,String?methodName,String[]?paramTypes,String[]?paramValues){
????????try{
????????????//?根據calssName得到class對象
????????????Class?cls?=?Class.forName(className);
????????????//?實例化對象
????????????Object?obj?=?cls.newInstance();
????????????//?根據參數類型數組得到參數類型的Class數組
????????????Class[]?parameterTypes?=?constructTypes(paramTypes);
????????????//?得到方法
????????????Method?method?=?cls.getMethod(methodName,?parameterTypes);
????????????//?根據參數類型數組和參數值數組得到參數值的obj數組
????????????Object[]?parameterValues?=?constructValues(paramTypes,paramValues);
????????????//?執行這個方法并返回obj值
????????????Object?returnValue?=?method.invoke(obj,?parameterValues);
????????????System.out.println("結果:"+returnValue);
????????}catch?(Exception?e){
????????????//?TODO?Auto-generated?catch?block
????????????e.printStackTrace();
????????}
????}
????private?static?Object[]?constructValues(String[]?paramTypes,String[]?paramValues){
????????Object[]?obj?=?new?Object[paramTypes.length];
????????for?(int?i?=?0;?i?<?paramTypes.length;?i++){
????????????if(paramTypes[i]?!=?null?&&?!paramTypes[i].trim().equals("")){
????????????????if?("Integer".equals(paramTypes[i])?||?"int".equals(paramTypes[i])){
????????????????????obj[i]?=?Integer.parseInt(paramValues[i]);
????????????????}else?if?("Double".equals(paramTypes[i])?||?"double".equals(paramTypes[i])){
????????????????????obj[i]?=?Double.parseDouble(paramValues[i]);
????????????????}else?if?("Float".equals(paramTypes[i])?||?"float".equals(paramTypes[i])){
????????????????????obj[i]?=?Float.parseFloat(paramValues[i]);
????????????????}else{
????????????????????obj[i]?=?paramTypes[i];
????????????????}
????????????}
????????}
????????return?obj;
????}
????("rawtypes")
????private?static?Class[]?constructTypes(String[]?paramTypes){
????????Class[]?cls?=?new?Class[paramTypes.length];
????????for?(int?i?=?0;?i?<?paramTypes.length;?i++){
????????????if(paramTypes[i]?!=?null?&&?!paramTypes[i].trim().equals("")){
????????????????if?("Integer".equals(paramTypes[i])?||?"int".equals(paramTypes[i])){
????????????????????cls[i]?=?Integer.class;
????????????????}else?if?("Double".equals(paramTypes[i])?||?"double".equals(paramTypes[i])){
????????????????????cls[i]?=?Double.class;
????????????????}else?if?("Float".equals(paramTypes[i])?||?"float".equals(paramTypes[i])){
????????????????????cls[i]?=?Float.class;
????????????????}else{
????????????????????cls[i]?=?String.class;
????????????????}
????????????}
????????}
????????return?cls;
????}
}
4. 總結:
文章開頭也有提到,平時的業務開發者中反射機制是比較少用到的,但是,總歸要學習的,萬一哪天用到了呢?
反射機制的優缺點:
優點:
運行期類型的判斷,動態類加載,動態代理使用反射。
缺點:
性能是一個問題,反射相當于一系列解釋操作,通知jvm要做的事情,性能比直接的java代碼要慢很多。
關于Java反射機制,需要明確幾點,反射到底是個怎么過程?反射的實際應用場景又有哪些?
前面JVM類加載機制時有張圖,拿來改造改造:
如果文章有錯的地方歡迎指正,大家互相留言交流。習慣在微信看技術文章,想要獲取更多的Java資源的同學,可以關注微信公眾號:niceyoo
posted @ 2019-03-24 22:07 niceyoo 閱讀(...) 評論(...) 編輯 收藏總結
以上是生活随笔為你收集整理的Java反射机制概念及应用场景的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 新概念4-41
- 下一篇: c:forEach 如何输出序号