反射的概念:
- 作用:在Java中,如果想要在除了編譯器之外的運行期也能夠檢查類,接口,變量以及方法的信息就可以通過反射動態的進行獲取。並且在Java大量的流行框架中例如Spring,都是以反射爲基礎來進行構建。所以反射的地位在Java中非常重要。
反射的一個demo(通過反射獲取類對象中的方法集)
//定一一個類對象
public class Cluber {
public void join() {
}
public void exit(){
}
}
//demo
public class BootStrapDemo {
public static void main(String[] args) {
Method[] methods = Cluber.class.getDeclaredMethods();
List<String> methodNames = Stream.of(methods).map(Method::getName).collect(Collectors.toList());
System.out.println(methodNames);
}
}
//結果
[exit, join]
反射的具體使用:
通過反射主要可以如下的類的信息:
- Class對象
- 類名
- 修飾符
- 包信息
- 父類
- 實現的接口
- 構造器
- 方法
- 變量
- 註解
1. 簡單介紹Class類以及你能從Class類中獲取哪些信息
//獲取類對象
Class cluberClass = Cluber.class;
try {
Class<?> cluberClass2 = Class.forName("Java_Reflection.demo.Cluber");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
}
//獲取類名
String className = cluberClass.getName();
//獲取類的修飾符 返回的是整型標識符
int modifiers = cluberClass.getModifiers();
//通過Modifier類來檢測具體的修飾符
boolean isPublic = Modifier.isPublic(modifiers);
//通過類對象獲取包信息
Package aPackage = cluberClass.getPackage();
aPackage.getName();
//獲取父類
Class superclass = cluberClass.getSuperclass();
//獲取實現的接口
Class[] interfaces = cluberClass.getInterfaces();
//獲取構造器
Constructor[] constructors = cluberClass.getConstructors();
//獲取所有方法
Method[] methods1 = cluberClass.getMethods();
//獲取所有變量
Field[] fields = cluberClass.getFields();
//獲取所有註解
Annotation[] annotations = cluberClass.getAnnotations();
}
2. 反射-構造器詳解
- 通過Java中的反射可以獲取類的構造器並且在運行期初始化對象。相關類java.reflect.Constructor
-
通過getConstructor()方法可以獲取類的所有public構造方法,每一個構造方法都對應一個Constructor對象
Constructor<?>[] constructors = cluberClass.getConstructors();
-
如果已知精確的構造器參數類型,可以通過參數類型直接獲取特定的構造方法對象。並且如果沒有該構造方法會拋出NoSuchMethodException的異常。
try { cluberClass.getConstructor(new Class[]{String.class,Integer.class}); } catch (NoSuchMethodException e) { e.printStackTrace(); }
-
獲取構造器中的參數(通過Constructor對象可以獲取構造函數的參數類型)
Class<?>[] parameterTypes = constructor.getParameterTypes();
-
通過構造器對象示例化對象
try { Cluber cluber = constructor.newInstance("test", 16); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); }
3. 反射-變量
- 通過反射可以在運行期獲取到類的成員變量並且對它們進行set/get操作。相關類==java.lang.reflect.Field
1.獲取所有的可訪問屬性(此種方式可以獲取所有可以訪問的變量的集合)
Field[] fields = Cluber.class.getFields();
- 獲取特定變量
Field field = null;
Field count = null;
//獲取特定屬性
try {
field = Cluber.class.getField("name");
count = Cluber.class.getField("count");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
-
獲取屬性名
`System.out.println(field.getName());`
-
變量類型
`Class<?> type = field.getType();`
-
獲取或者設置屬性值(注意如果是設置static,則不用指定對象)
//get/set屬性
Cluber cluber = new Cluber();
try {
field.set(cluber, "zjf");
count.set(null, 100);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
System.out.println(cluber.getName() + "===" + Cluber.count);
4. 反射-方法
- 通過反射可以在運行期獲取類的方法對象並且可以調用該方法。相關類java.lang.reflect.Method
1.獲取所有Method對象
Method[] methods = cluberClass.getMethods();
2.獲取指定Method(需要指定方法名和參數類型如果沒有則爲null)
//獲取指定方法
try {
test = cluberClass.getMethod("test", new Class[]{String.class});
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
exit = cluberClass.getMethod("exit", null);
} catch (NoSuchMethodException e) {
}
3.獲取方法參數和返回值
Class<?>[] parameterTypes = test.getParameterTypes();
Class<?> returnType = test.getReturnType();
4.調用方法(如果是非靜態方法需要指定調用的對象和參數,如果是靜態方法則調用對象是null)
Cluber cluber = new Cluber();
try {
test.invoke(cluber, "zjf");
exit.invoke(cluber,null);
staticMethod.invoke(null);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
5. 反射-私有變量和方法
- 通過反射也可以檢查私有方法和私有變量
Class<Cluber> cluberClass = Cluber.class;
//獲取所有的方法包括私有方法
Method[] declaredMethods = cluberClass.getDeclaredMethods();
System.out.println(Arrays.toString(declaredMethods));
try {
Field address = cluberClass.getDeclaredField("address");
Method init = cluberClass.getDeclaredMethod("init");
//需要設置setAccessible 爲true 才能對private屬性和方法進行操作
init.setAccessible(true);
address.setAccessible(true);
Cluber cluber = new Cluber();
init.invoke(cluber);
String addr = (String) address.get(cluber);
System.out.println("===private Field===" + address.getName() + "===values===" + addr);
} catch (Exception e) {
e.printStackTrace();
}
5. 反射-註解
- 通過反射在運行時獲取類的註解的信息,需要注意的是getDeclaredAnnotations得到的是當前成員所有的註釋,不包括繼承的。而getAnnotations得到的是包括繼承的所有註釋。
Class<Cluber> cluberClass = Cluber.class;
//獲取類的所有註解
Annotation[] annotations = cluberClass.getAnnotations();
System.out.println(Arrays.toString(annotations));
//獲取指定類的註解
MyAnnotation myAnnotation = cluberClass.getAnnotation(MyAnnotation.class);
//獲取註解的屬性
int age = myAnnotation.age();
String name = myAnnotation.name();
System.out.println("name is " + name + ",age is " + age);
try {
//獲取方法的註解
//獲取參數的註解 首先需要獲取指定方法的對象 通過方法來獲取參數的註解信息
Method test = cluberClass.getMethod("test", new Class[]{String.class});
Annotation[] declaredAnnotations = test.getDeclaredAnnotations();
System.out.println(Arrays.toString(declaredAnnotations));
//獲取方法的指定註解
MyAnnotation declaredAnnotation = cluberClass.getDeclaredAnnotation(MyAnnotation.class);
System.out.println("方法的註解myAnnotation,屬性 name is " + declaredAnnotation.name() + ",age is " + declaredAnnotation.age());
//參數的註解返回的是一個二維數組以此來表示多個參數可能有多個註解的情況
Annotation[][] parameterAnnotations = test.getParameterAnnotations();
Class<?>[] parameterTypes = test.getParameterTypes();
for (Annotation[] annos : parameterAnnotations) {
for (Annotation annotation : annos) {
if (annotation instanceof MyAnnotation) {
System.out.println("方法參數的註解myAnnotation,屬性 name is " + declaredAnnotation.name() + ",age is " + declaredAnnotation.age());
}
}
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
//獲取屬性的註解
Field field = null;
try {
field = cluberClass.getField("name");
Annotation[] fieldDeclaredAnnotations = field.getDeclaredAnnotations();
for (Annotation annotation : fieldDeclaredAnnotations) {
if (annotation instanceof MyAnnotation) {
System.out.println("屬性的註解myAnnotation,屬性 name is " + ((MyAnnotation) annotation).name() + ",age is " + ((MyAnnotation) annotation).age());
}
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
5. 反射-泛型
- 通過反射可以在運行期動態的獲取泛型參數的信息,泛型方法的返回值的信息和泛型參數的信息。
ParameterizedType表示的是參數化類型對象
- 定義一個泛型類
public class GenericDemo<String> {
public List<String> list;
public List<String> getStringList(List<String> param) {
return null;
}
}
- 通過反射獲取泛型的相關信息
Class<GenericDemo> genericDemoClass = GenericDemo.class;
try {
//1.獲取泛型方法的返回值的參數化類型信息
Method getStringList = genericDemoClass.getMethod("getStringList", new Class[]{List.class});
//獲取泛型返回值
Type genericReturnType = getStringList.getGenericReturnType();
System.out.println(genericReturnType.getTypeName());
if (genericReturnType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericReturnType;
//獲取返回值的類型參數
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
System.out.println("泛型參數類型: " + Arrays.toString(actualTypeArguments));
}
//2.獲取方法泛型參數的類型信息
//獲取方法的所有的泛型參數類型
Type[] genericParameterTypes = getStringList.getGenericParameterTypes();
for (Type type : genericParameterTypes) {
if (type instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
System.out.println("方法的泛型參數的類型信息: " + Arrays.toString(actualTypeArguments));
}
}
//獲取泛型變量類型
Field list = genericDemoClass.getField("list");
Type genericType = list.getGenericType();
if (genericType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments();
System.out.println("泛型變量的類型信息:" + Arrays.toString(actualTypeArguments));
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
6. 反射-數組
- 通過反射可以動態地創建數組、操作數組並且也可以獲取數組的類型對象信息。核心對象是java.lang.reflect.Array
public static Class getClass(String className) {
if ("int".equals(className)) {
return int.class;
}
if ("long".equals(className)) {
return long.class;
}
if ("short".equals(className)) {
return short.class;
}
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
//1 通過反射來創建一個數組
int[] intArray = (int[]) Array.newInstance(int.class, 10);
//2.通過反射訪問數組
for (int i = 0; i < intArray.length; i++) {
Array.set(intArray, i, i);
}
System.out.println(Arrays.toString(intArray));
int first = (int) Array.get(intArray, 0);
System.out.println("第一個元素爲: " + first);
//獲取數組的Class對象
//不通過反射
Class aClass = String[].class;
//通過反射
try {
//原生數據類型的獲取
Class intClass = Class.forName("[I");
Class stringArrayClass = Class.forName("[Ljava.lang.String;");
//通過反射獲取數組類型對象
Class aClass1 = getClass("int");
Class arrayClassType = Array.newInstance(aClass1, 0).getClass();
//驗證是否爲數組類型對象
boolean array = arrayClassType.isArray();
System.out.println(array == true ? "是數組類型" : "不是數組類型對象");
//獲取數組的成員類型
Class<? extends int[]> aClass2 = intArray.getClass();
Class<?> componentType = aClass2.getComponentType();
System.out.println("數組成員類型:" + componentType);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}