Java反射以及应用
需求:需要通過反射動態獲取類的字段類型,然后做特殊處理
?
?
Java反射getDeclaredField和getField的區別
getDeclaredFiled 只能獲取類本身的屬性成員(包括私有、共有、保護)?
getField 僅能獲取類(及其父類可以自己測試) public屬性成員
反射獲取所有的字段
Class clazz = 類.class;
Field[] fields= classzz.getDeclaredFields();
獲得某個具體字段,并獲取類型
String fieldType=clazz.getDeclaredField("需要獲取的字段").getType().toString();
if(fieldType.contains("Integer")||fieldType.contains("Long")){
//這里做業務處理
}
?
下面再看一個完整的例子:
public class User {public String name;public int age;public String address;
}
public static void getFieldsValue(Object obj) {Field[] fields = obj.getClass().getDeclaredFields();/*** 基本類型、包裝類型、String類型*/String[] types = {"java.lang.Integer","java.lang.Double","java.lang.Float","java.lang.Long","java.lang.Short","java.lang.Byte","java.lang.Boolean","java.lang.Character","java.lang.String","int","double","long","short","byte","boolean","char","float"};for(Field f : fields){f.setAccessible(true);try {for(String str : types) {if(f.getType().getName().equals(str))System.out.println("字段:"+f.getName()+" 類型:"+f.getType().getName()+" 值:"+ f.get(obj));}} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}}
獲取更多類型方法:
Java-使用反射獲取類型信息:https://blog.csdn.net/alisonyu/article/details/82762765?
數組類型
數組類型不像其他的類型可以通過isAssignableFrom()函數來進行判斷,他需要使用isArray()?來判斷該type是否是一個數組類型,然后使用getComponentType()?獲取他的元素的類型
public void queryArrayType() throws NoSuchFieldException {Field field = Some.class.getDeclaredField("具體字段");Class<?> type = field.getType();//一般來說,判斷是否是某種類型是可以使用isAssignableFrom// 判斷是否是數組類型比較特殊,要使用isArray()這個函數if (type.isArray()){//獲得數組的類型,使用getComponentType()這個方法Class<?> componentType = type.getComponentType();assertEquals(componentType,Integer.class);}else{throw new IllegalStateException();}
}
帶泛型的類型
ParameterizedType表示參數化的類型,例如Collection這樣的類型。我們可以通過getGenericType()方法獲得該子類,當你的類型帶有參數的時候就會返回ParameterizedType,否則會返回普通的類型(class)
public void getListType() throws NoSuchFieldException {Field field = Some.class.getDeclaredField("list");//如果類似于List<String>這樣的類型就是一種GenericType//注意這是一種Type類型Type type = field.getGenericType();if (type instanceof ParameterizedType){//泛型參數類型ParameterizedType parameterizedType = (ParameterizedType)type;Type[] actualTypes = parameterizedType.getActualTypeArguments();//因為List<String>獲得第一個泛型參數,因為只有一個,我們取第一個//如果我們有多個泛型參數,我們可以根據順序取不同的泛型參數assertEquals(actualTypes[0],String.class);//如果獲得List這個原始類型呢?assertEquals(parameterizedType.getRawType(),List.class);}else{throw new IllegalStateException();}
}
下面是我以前寫的關于反射的筆記,如果有對反射基礎知識不清楚的需要補課:
說明:
Class這個Java類保存的是一個Java類的meta信息(元信息)。一般在反射中使用。?
Object類,是所有Java類的根。包括Class類。
?
Class類:用于描述一切類/接口.枚舉是一種類,注解是一種接口
Class實例:就是指JVM中一份字節碼
Class類:用于描述一切類/接口.問題:那Class實例到底表示的是哪一份字節碼,為了明確區分出Class實例表示的是誰的字節碼.Class類提供了泛型
Class<Date> ?clz1 = Date.class;//clz1表示是Date的字節碼
Class<String> ?clz2 = String.class;//clz2表示的是String的字節碼
如何得到Class的實例:
? ? ?1.類名.class(就是一份字節碼)
? ? ?2.Class.forName(String className);根據一個類的全限定名來構建Class對象
? ? ?3.每一個對象多有getClass()方法:obj.getClass();返回對象的真實類型
?一個類在JVM中只有一份字節碼;
第一種方式:數據類型.class
? Class<User> clz1 = User.class;
第二種方式: Class.forName(String className);
Class<?> ?clz2 = Class.forName("cn.itcast.cd.User");
使用?是因為此時Class不知道類,因為傳的是字符串
反射很強大,但是耗性能.主要是為了做工具和框架使用的.
第三種方式: ?對象.getClass();得到對象的真實類型,每個方法都有所以在Object里
User u ?= new User();
? ?Class clz3 = u.getClass();
clz1 == clz2 == clz3:因為表示都是JVM中共同的一份字節碼(User.class)
new一個類才會把字節碼從IO加載到內存。
?
Java內置9大的Class實例
對于對象來說,可以直接使用對象.getClass()或者Class.forName(className); 類名.class都可以獲取Class實例.
但是我們的基本數據類型,就沒有類的權限定名,也沒有getClass方法.
問題:那么如何使用Class類來表示基本數據類型的Class實例?
byte,short,int,long,char,float,double,boolean ,void關鍵字
上述8種類型和void關鍵字,都有class屬性.
表示int的Class對象: ?Class clz = int.class;
表示boolean的Class對象: ?boolean.class;
void: ?Class clz = void.class;
所有的數據類型都有class屬性,表示都是Class對象.
思考:
int的包裝類是Integer
Integer.class ? ? ==?== ? ? ? ? int.class
結果是false,說明是兩份字節碼.
Integer 和int是同一種數據類型嗎? 不是
但是在八大基本數據類型的包裝類中都有一個常量:TYPE
TYPE表示的是該包裝類對應的基本數據類型的Class實例.
如:Integer.TYPE----->int.class
? ?Integer.TYPE==int.class;//YES
? ?Integer.TYPE == Integer.class;//ERROR
?
數組的Class實例:
String[] sArr1 = {"A","C"};
String[] sArr2 = {};
String[][] sArr = {};
int[] sArr = {};
表示數組的Class實例:
? ?String[] sArr1 = {"A","C"};
? ?Class clz = String[].class;//此時clz表示就是一個String類型的一位數組類型
? ?所有具有相同元素類型和維數的數組才共享同一份字節碼(Class對象);
? ?注意:和數組中的元素沒有一點關系.
?
獲取類中的構造器
獲取某一個類中的所有的構造器:
? ?1,明確操作的是哪一份字節碼對象
? ?2,獲取構造器
Class類獲取構造器方法:
Constructor類:表示類中構造器的類型,Constructor的實例就是某一個類中的某一個構造器
public Constructor<?>[] getConstructors():該方法只能獲取當前Class所表示類的public修飾的構造器
public Constructor<?>[] getDeclaredConstructors():獲取當前Class所表示類的所有的構造器,和訪問權限無關
public Constructor<T> getConstructor(Class<?>... parameterTypes) :獲取當前Class所表示類中指定的一個public的構造器
? ? ? 參數:parameterTypes表示:構造器參數的Class類型
? ? ? 如:public User(String name)
? ? ? ? Constructor c = ?clz.getConstructor(String.class);
?
public class User {public User(){};public User(String name){};public User(String name,String school){};
}
?
? ? ? ?System.out.println(Integer.TYPE);Class<User> clz=User.class;Constructor[]cs=clz.getConstructors();for (Constructor c : cs) {System.out.println(c);}//獲取單個構造器Constructor c=clz.getDeclaredConstructor(String.class);System.out.println(c);
?
?
?
調用構造器,創建對象
Constructor<T>類:表示類中構造器的類型,Constructor的實例就是某一個類中的某一個構造器
常用方法:
public T newInstance(Object... initargs):如調用帶參數的構造器,只能使用該方式.
? ? ?參數:initargs:表示調用構造器的實際參數
? ? ?返回:返回創建的實例,T表示Class所表示類的類型
如果:一個類中的構造器可以直接訪問,同時沒有參數.,那么可以直接使用Class類中的newInstance方法創建對象.
?public Object newInstance():相當于new 類名();
?
?
修改User
?
public class User {public User() {System.out.println("---");}public User(String name) {System.out.println(name);}public User(String name, String school) {System.out.println(name + " " + school);}
}
?
public static void main(String[] args) throws Exception { System.out.println(Integer.TYPE);Class<User> clz=User.class;Constructor[]cs=clz.getConstructors();for (Constructor c : cs) {System.out.println(c);}//獲取單個構造器//泛型Constructor<User> c=clz.getDeclaredConstructor(String.class);System.out.println(c); User u=c.newInstance("abc");//不帶泛型Constructor c2=clz.getDeclaredConstructor(String.class);System.out.println(c2); Object u2=c2.newInstance("abc"); }
?
?
?
?
?
?
Class.forName方式
?
如果訪問不帶參數的構造器可以直接用Class的newInstance()方法
?
修改訪問權限為private
?
public class User {public User() {System.out.println("---");}private User(String name) {System.out.println(name);}public User(String name, String school) {System.out.println(name + " " + school);}
}
報錯
?
?
Constructor<User> c=clz.getDeclaredConstructor(String.class);System.out.println(c);c.setAccessible(true);User u=c.newInstance("abc");
?
獲取類中的方法
?
使用反射獲取某一個類中的方法:
1.找到獲取方法所在類的字節碼對象
2.找到需要被獲取的方法
Class類中常用方法:
public Method[] getMethods():獲取包括自身和繼承過來的所有的public方法
public Method[] getDeclaredMethods():獲取自身所有的方法(不包括繼承的,和訪問權限無關)
public Method getMethod(String methodName,
? ? ? ? ? ? ? ? ? ? ? ? Class<?>... parameterTypes):表示調用指定的一個公共的方法(包括繼承的)
? ? ? ?參數:
? ? ? ? ? ? ? ?methodName: 表示被調用方法的名字
? ? ? ? ? ? ? ?parameterTypes:表示被調用方法的參數的Class類型如String.class
public Method getDeclaredMethod(String name,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Class<?>... parameterTypes):表示調用指定的一個本類中的方法(不包括繼承的)
? ? ? ? 參數:
? ? ? ? ? ? ? ?methodName: 表示被調用方法的名字
? ? ? ? ? ? ? ?parameterTypes:表示被調用方法的參數的Class類型如String.class
?
?
public class User {public User() {System.out.println("---");}public User(String name) {System.out.println(name);}public User(String name, String school) {System.out.println(name + " " + school);}public void Say(String name) {System.out.println(name);}public void Say(String name, String school) {System.out.println(name + " " + school);}
}
?
Class clz=User.class;Method[] m=clz.getMethods();for (Method c : m) {System.out.println(c);}System.out.println("----------------------");m=clz.getDeclaredMethods();for (Method c : m) {System.out.println(c);}
?
?
?
?
Method m1=clz.getMethod("Say", String.class);System.out.println(m1);Method m2=clz.getMethod("Say", String.class,String.class);System.out.println(m2);
?
總結
以上是生活随笔為你收集整理的Java反射以及应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 为什么jdk源码推荐ThreadLoca
- 下一篇: 软件体系架构模式之一什么是软件架构模式