Java - 反射及其使用
Java 开发人员必须要知道的一个知识,就是反射,在看很多底层源码的时候或多或少都会涉及一些,下面来介绍一下
前言
Java 一种经典的面向对象开发语言,对象先声明后使用,而一个变量又分为 编译型类型 与 运行时类型
- 编译时类型 是由声明该变量时使用的类型决定
- 运行时类型 由实际赋给该变量的对象决定
若编译时类型和运行时类型不一致,也就是我们所谓的 多态。因为子类其实是一种特殊的父类,因此java允许把一个子类对象直接赋值给一个父类引用变量,无须任何类型转换,或者被称为向上转型,由系统自动完成。引用变量在编译阶段只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所具有的方法
前期准备
为方便下面的方法示例,这里做一些准备工作,新建几个类
1、新建一个类 StudyParamParentPre
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class StudyParamParentPre {
String namePrePre;
List<String> listPrePre;
List<List<String>> dListPrePre;
public void publicGetParentPre() {
}
protected void protectedGetParentPre() {
}
private void privateGetParentPre() {
}
}
2、新建一个类 StudyParamParent,其是StudyParamParentPre 的子类
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class StudyParamParent extends StudyParamParentPre{
String namePre;
List<String> listPre;
List<List<String>> dListPre;
public void publicGetParent() {
}
protected void protectedGetParent() {
}
private void privateGetParent() {
}
}
3、新建一个接口 StudyInfer
public interface StudyInfer {
public void publicGetInfer();
}
4、新建一个类 StudyParam,其是 StudyParamParent 的子类,实现了 StudyInfer
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class StudyParam extends StudyParamParent implements StudyInfer {
String name;
List<String> list;
String[] strings;
List<List<String>> dList;
public StudyParam(String namePre, List<String> listPre, List<List<String>> dListPre, String name) {
super(namePre, listPre, dListPre);
this.name = name;
}
private StudyParam(String namePre, List<String> listPre, List<List<String>> dListPre, String name, List<String> list) {
super(namePre, listPre, dListPre);
this.name = name;
this.list = list;
}
public void publicGet() {
}
protected void protectedGet() {
}
private void privateGet() {
}
@Override
public void publicGetInfer() {
}
public void getPublicHa() {
}
public void getPublicHa(String name) {
}
private void getPrivateHa() {
}
private void getPrivateHa(String name) {
}
}
反射
什么是反射?
反射 就是在运行状态中,能够知道任意类所有属性和方法,可调用其任意一个方法和属性,即动态获取信息及动态调用对象方法的功能叫 Java 反射
反射可以做什么?
在运行状态中,反射可以做以下事情:
- 判断任意一个对象所属的类,实例化该对象
- 获得任意一个对象的属性,可修改该属性的值
- 获得任意一个对象的方法,可反射执行该方法
反射如何使用?
因为Java是面向对象编程,最基础的就是类,即 Class
Class
面向对象编程,故基础为类,属性与方法都基于类,该类中有的方法常用的如下:
方法名称 | 用途 | 返回值 |
---|---|---|
toString toGenericString | 对象转换为String | String |
isInstance isAssignableFrom isInterface isArray isPrimitive isAnnotation isSynthetic isAnnotationPresent isAnonymousClass isLocalClass isMemberClass isEnum | 是否是某实例 是否从xx 继承/实现来的 是否是接口 是否是数组 是否是原始类型 是否是注解 是否是Synthetic 是否是注解 是否是匿名类 是否是局部变量 是否是Member 是否是枚举 | boolean |
newInstance | 实例化对象 | T |
getName getSimpleName getTypeName getCanonicalName | 获取类的全类名 | String |
getSuperclass getGenericSuperclass | 获取父类 | Class<? super T> Type |
getPackage | 获取类所在的包 | Package |
getComponentType | 返回表示数组组件类型的 Class | Class<?> |
getClassLoader | 获取类加载器 | ClassLoader |
说明:
- toString 与 toGenericString 的返回值去吧在于一个是全类名的名称字符串,一个是包含了访问符、类类型的字符串
- getName 与 getSimpleName,getName包含包名和类名、getSimpleName为类名
方法使用举例:
package com.study;
import com.study.pojo.StudyInfer;
import com.study.pojo.StudyParam;
import com.study.pojo.StudyParamParent;
import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
public class Study {
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
Class<StudyParam> studyParamClass = StudyParam.class;
Class<StudyParamParent> studyParamParent = StudyParamParent.class;
System.out.println("-------- class toString -------- ");
System.out.println(studyParamClass.toString());
//class com.study.pojo.StudyParam
System.out.println("-------- class toGenericString -------- ");
System.out.println(studyParamClass.toGenericString());
//public class com.study.pojo.StudyParam
System.out.println("-------- class isInstance -------- ");
System.out.println(studyParamClass.isInstance(new StudyParam()));
System.out.println(studyParamClass.isInstance(new StudyParamParent()));
//true
//false
System.out.println("-------- class isAssignableFrom -------- ");
System.out.println(studyParamClass.isAssignableFrom(StudyParamParent.class));
System.out.println(studyParamClass.isAssignableFrom(StudyInfer.class));
System.out.println(studyParamParent.isAssignableFrom(StudyParam.class));
//false
//false
//true
System.out.println("-------- class isInterface -------- ");
System.out.println(studyParamClass.isInterface());
// false
System.out.println("-------- class isArray -------- ");
System.out.println(studyParamClass.isArray());
// false
System.out.println("-------- class isPrimitive -------- ");
System.out.println(studyParamClass.isPrimitive());
// false
System.out.println("-------- class isAnnotation -------- ");
System.out.println(studyParamClass.isAnnotation());
// false
System.out.println("-------- class getName -------- ");
System.out.println(studyParamClass.getName());
// com.study.pojo.StudyParam
System.out.println("-------- class getSimpleName -------- ");
System.out.println(studyParamClass.getSimpleName());
// StudyParam
System.out.println("-------- class getCanonicalName -------- ");
System.out.println(studyParamClass.getCanonicalName());
// com.study.pojo.StudyParam
System.out.println("-------- class getTypeName -------- ");
System.out.println(studyParamClass.getTypeName());
//com.study.pojo.StudyParam
System.out.println("-------- class getInterfaces -------- ");
Class<?>[] interfaces = studyParamClass.getInterfaces();
for (Class<?> interfacess : interfaces) {
System.out.println(interfacess);
}
//interface com.study.pojo.StudyInfer
System.out.println("-------- class getSuperclass -------- ");
Class<? super StudyParam> superclass = studyParamClass.getSuperclass();
System.out.println(superclass);
// class com.study.pojo.StudyParamParent
System.out.println("-------- class getGenericSuperclass -------- ");
Type genericSuperclass = studyParamClass.getGenericSuperclass();
System.out.println(genericSuperclass.getTypeName());
// com.study.pojo.StudyParamParent
System.out.println("-------- class getPackage -------- ");
Package aPackage = studyParamClass.getPackage();
System.out.println(aPackage.getName());
// com.study.pojo
System.out.println("-------- class getComponentType -------- ");
StudyParam studyParam = studyParamClass.newInstance();
studyParam.setStrings(new String[]{"1"});
Class<?> componentType = studyParamClass.getComponentType();
Class<?> componentType1 = studyParam.getStrings().getClass().getComponentType();
System.out.println(componentType);
System.out.println(componentType1);
//null
//class java.lang.String
System.out.println("-------- class getClassLoader -------- ");
ClassLoader classLoader = studyParamClass.getClassLoader();
System.out.println(classLoader);
// sun.misc.Launcher$AppClassLoader@18b4aac2
}
}
1、获取Class
涉及的方法如下:
方法名称 | 用途 | 返回值 |
---|---|---|
forname | 根据类全类名称获取类 | Class |
获取 Class 有四种方式:
- Class.forname:根据类的全类名来获取
- xxx.class:根据类来获取
- new xxx().getClass():根据实例对象来获取
- classloader.loadClass:根据类加载器加载
example:
Class clazz1 = Class.forName("com.study.pojo.StudyParam");
Class clazz2 = GenericTest.class;
Class clazz3 = new GenericTest().getClass();
ClassLoader loader = null;
loader.loadClass("com.study.pojo.StudyParam");
2、获取Class 中的方法(Method、Constructor)
类中有很多方法,包括:
- 构造器
- 私有(private)方法
- 公共(public)方法
- 保护(protected)方法
- 默认(default)方法
- 父类继承 / 接口实现的方法
常用获取类中方法的方式如下:
方法名称 | 用途 | 返回值 |
---|---|---|
getMethods | 或者本类以及父类或者父接口中所有的公共方法 | Method[] |
getMethod | 获取本类以及父类或者父接口中所有的公共方法指定的Method | Method |
getDeclaredMethod | 获取本类所有的方法中指定的Method,不包括继承的方法 | Method |
getDeclaredMethods() | 获取本类所有的方法,不包括继承的方法 | Method[] |
getConstructors getDeclaredConstructors | 获取所有的构造方法 getConstructors包含所有的公共构造方法 getDeclaredConstructors 包含所有的构造方法 | Constructor[] |
getConstructor | 获取指定构造方法 | Constructor |
方法使用举例:
package com.study;
import com.study.pojo.StudyInfer;
import com.study.pojo.StudyParam;
import com.study.pojo.StudyParamParent;
import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
public class Study {
public static void main(String[] args) throws NoSuchMethodException {
Class<StudyParam> studyParamClass = StudyParam.class;
System.out.println("-------- class getConstructors -------- ");
Constructor<?>[] constructors = studyParamClass.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
//public com.study.pojo.StudyParam()
//public com.study.pojo.StudyParam(java.lang.String,java.util.List,java.lang.String[],java.util.List)
//public com.study.pojo.StudyParam(java.lang.String,java.util.List,java.util.List,java.lang.String)
System.out.println("-------- class getConstructor -------- ");
Constructor<StudyParam> constructor = studyParamClass.getConstructor(String.class, List.class, List.class, String.class);
System.out.println(constructor);
//public com.study.pojo.StudyParam(java.lang.String,java.util.List,java.util.List,java.lang.String)
System.out.println("-------- class getDeclaredConstructors -------- ");
Constructor<?>[] declaredConstructors = studyParamClass.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
//public com.study.pojo.StudyParam()
//public com.study.pojo.StudyParam(java.lang.String,java.util.List,java.lang.String[],java.util.List)
//private com.study.pojo.StudyParam(java.lang.String,java.util.List,java.util.List,java.lang.String,java.util.List)
//public com.study.pojo.StudyParam(java.lang.String,java.util.List,java.util.List,java.lang.String)
System.out.println("-------- class getDeclaredConstructor -------- ");
Constructor<StudyParam> declaredConstructor = studyParamClass.getDeclaredConstructor(String.class, List.class, List.class, String.class, List.class);
System.out.println(declaredConstructor);
//private com.study.pojo.StudyParam(java.lang.String,java.util.List,java.util.List,java.lang.String,java.util.List)
System.out.println("-------- class getMethods -------- ");
Method[] methods = studyParamClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
//public java.lang.String com.study.pojo.StudyParam.toString()
//public java.lang.String com.study.pojo.StudyParam.getName()
//public void com.study.pojo.StudyParam.setName(java.lang.String)
//public void com.study.pojo.StudyParam.setDList(java.util.List)
//public void com.study.pojo.StudyParam.publicGetInfer()
//public java.util.List com.study.pojo.StudyParam.getList()
//public java.util.List com.study.pojo.StudyParam.getDList()
//public void com.study.pojo.StudyParam.setList(java.util.List)
//public void com.study.pojo.StudyParam.getPublicHa()
//public void com.study.pojo.StudyParam.getPublicHa(java.lang.String)
//public java.lang.String[] com.study.pojo.StudyParam.getStrings()
//public void com.study.pojo.StudyParam.setStrings(java.lang.String[])
//public void com.study.pojo.StudyParam.publicGet()
//public void com.study.pojo.StudyParamParent.setDListPre(java.util.List)
//public void com.study.pojo.StudyParamParent.publicGetParent()
//public java.util.List com.study.pojo.StudyParamParent.getListPre()
//public void com.study.pojo.StudyParamParent.setNamePre(java.lang.String)
//public void com.study.pojo.StudyParamParent.setListPre(java.util.List)
//public java.util.List com.study.pojo.StudyParamParent.getDListPre()
//public java.lang.String com.study.pojo.StudyParamParent.getNamePre()
//public void com.study.pojo.StudyParamParentPre.publicGetParentPre()
//public java.util.List com.study.pojo.StudyParamParentPre.getDListPrePre()
//public java.lang.String com.study.pojo.StudyParamParentPre.getNamePrePre()
// public void com.study.pojo.StudyParamParentPre.setDListPrePre(java.util.List)
//public void com.study.pojo.StudyParamParentPre.setListPrePre(java.util.List)
//public void com.study.pojo.StudyParamParentPre.setNamePrePre(java.lang.String)
//public java.util.List com.study.pojo.StudyParamParentPre.getListPrePre()
//public final void java.lang.Object.wait() throws java.lang.InterruptedException
//public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
//public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
//public boolean java.lang.Object.equals(java.lang.Object)
//public native int java.lang.Object.hashCode()
//public final native java.lang.Class java.lang.Object.getClass()
//public final native void java.lang.Object.notify()
//public final native void java.lang.Object.notifyAll()
System.out.println("-------- class getMethod -------- ");
Method getPublicHa = studyParamClass.getMethod("getPublicHa", String.class);
System.out.println(getPublicHa);
//public void com.study.pojo.StudyParam.getPublicHa(java.lang.String)
System.out.println("-------- class getDeclaredMethods -------- ");
Method[] declaredMethods = studyParamClass.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method);
}
//public java.lang.String com.study.pojo.StudyParam.toString()
//public java.lang.String com.study.pojo.StudyParam.getName()
//public void com.study.pojo.StudyParam.setName(java.lang.String)
//public void com.study.pojo.StudyParam.setDList(java.util.List)
//public void com.study.pojo.StudyParam.publicGetInfer()
//private void com.study.pojo.StudyParam.privateGet()
//public java.util.List com.study.pojo.StudyParam.getList()
//public java.util.List com.study.pojo.StudyParam.getDList()
//public void com.study.pojo.StudyParam.setList(java.util.List)
//public void com.study.pojo.StudyParam.getPublicHa()
//public void com.study.pojo.StudyParam.getPublicHa(java.lang.String)
//public java.lang.String[] com.study.pojo.StudyParam.getStrings()
//public void com.study.pojo.StudyParam.setStrings(java.lang.String[])
//private void com.study.pojo.StudyParam.getPrivateHa(java.lang.String)
//private void com.study.pojo.StudyParam.getPrivateHa()
//public void com.study.pojo.StudyParam.publicGet()
//protected void com.study.pojo.StudyParam.protectedGet()
System.out.println("-------- class getDeclaredMethod -------- ");
Method getPrivateHa = studyParamClass.getDeclaredMethod("getPrivateHa", String.class);
System.out.println(getPrivateHa);
//private void com.study.pojo.StudyParam.getPrivateHa(java.lang.String)
}
}
3、获取Class 中的Filed
类中有很多属性,包括:
- 私有(private)属性
- 公共(public)属性
- 保护(protected)属性
- 默认(default)属性
- 父类继承的属性
常用获取类中属性的方式如下:
方法名称 | 用途 | 返回值 |
---|---|---|
getFields getDeclaredFields | 获取当前类和父类中 public 类型的 所有属性 获取当前类中的所有属性(public、protected、default、private) | Field[] |
getField getDeclaredField | 获取当前类和父类中 public 类型的 指定属性 获取当前类中的指定属性(public、protected、default、private) | Field |
方法使用举例:
package com.study;
import com.study.pojo.StudyInfer;
import com.study.pojo.StudyParam;
import com.study.pojo.StudyParamParent;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;
public class Study {
public static void getFiledInfo() throws NoSuchFieldException {
Class<StudyParam> studyParamClass = StudyParam.class;
System.out.println("-------- class getFields -------- ");
Field[] fields = studyParamClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
// 无
System.out.println("-------- class getField -------- ");
Field name = studyParamClass.getField("name");
System.out.println(name);
// 无
System.out.println("-------- class getDeclaredFields -------- ");
Field[] declaredFields = studyParamClass.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println(field);
}
//java.lang.String com.study.pojo.StudyParam.name
//java.util.List com.study.pojo.StudyParam.list
//java.lang.String[] com.study.pojo.StudyParam.strings
//java.util.List com.study.pojo.StudyParam.dList
System.out.println("-------- class getDeclaredField -------- ");
Field declaredField = studyParamClass.getDeclaredField("name");
System.out.println(declaredField);
//java.lang.String com.study.pojo.StudyParam.name
}
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, NoSuchFieldException {
getFiledInfo();
}
}
Method
为了下面的示例,在上述的 StudyParam 类中新增一个方法
package com.study.pojo;
import lombok.*;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class StudyParam extends StudyParamParent implements StudyInfer {
public <T extends Throwable> List<String> getPublicHa(String name, String hhh, List<String> l, List<List<String>> ll) throws T, NullPointerException {
System.out.println("getPublicHa invoke process");
return new ArrayList<>();
}
}
类中的方法为Method,Method常用的方法如下:
方法名称 | 用途 | 返回值 |
---|---|---|
toString() toGenericString | 方法的名称字符串 | String |
isBridge isVarArgs isSynthetic isDefault | 是否是xxx,与上面的雷同 | boolean |
getReturnType getGenericReturnType | 返回方法返回值类型 | Class<?> Type |
getParameterTypes getGenericParameterTypes | 返回方法参数值类型 | Class<?>[] Type[] |
getExceptionTypes getGenericExceptionTypes | 返回方法异常抛出类型 | Class<?>[] Type[] |
getName | 获取方法名称 | String |
invoke | 方法执行 | |
getParameterCount | 获取方法的参数数量 | int |
getTypeParameters | 获取方法一共都用了哪些泛型参数 | TypeVariable[] |
setAccessible | 设置方法可访问 |
说明:(getGenericxxxx 这种相比较 getxxxx ,若涉及泛型会输出泛型里面参数的具体类型)
- getReturnType、getGenericReturnType :返回方法返回值类型
- getParameterTypes、getGenericParameterTypes :返回方法参数值类型
- getExceptionTypes、getGenericExceptionTypes :返回方法异常抛出类型
- invoke:方法反射执行
方法使用举例:
package com.study;
import com.study.pojo.StudyInfer;
import com.study.pojo.StudyParam;
import com.study.pojo.StudyParamParent;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;
public class Study {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, NoSuchFieldException {
method();
}
public static void method() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<StudyParam> studyParamClass = StudyParam.class;
StudyParam studyParam = new StudyParam();
Method getPublicHa = studyParamClass.getMethod("getPublicHa", String.class ,String.class ,List.class,List.class);
System.out.println("-------- method toString -------- ");
String toString = getPublicHa.toString();
System.out.println(toString);
// public java.util.List com.study.pojo.StudyParam.getPublicHa(java.lang.String,java.lang.String,java.util.List,java.util.List) throws java.lang.Throwable,java.lang.NullPointerException
System.out.println("-------- method toGenericString -------- ");
String toGenericString = getPublicHa.toGenericString();
System.out.println(toGenericString);
// public <T> java.util.List<java.lang.String> com.study.pojo.StudyParam.getPublicHa(java.lang.String,java.lang.String,java.util.List<java.lang.String>,java.util.List<java.util.List<java.lang.String>>) throws T,java.lang.NullPointerException
System.out.println("-------- method isDefault -------- ");
boolean defaults = getPublicHa.isDefault();
System.out.println(defaults);
//false
System.out.println("-------- method getName -------- ");
String name = getPublicHa.getName();
System.out.println(name);
// getPublicHa
System.out.println("-------- method getParameterCount -------- ");
int parameterCount = getPublicHa.getParameterCount();
System.out.println(parameterCount);
// 4
System.out.println("-------- method getReturnType -------- ");
Class<?> returnType = getPublicHa.getReturnType();
System.out.println(returnType);
// interface java.util.List
System.out.println("-------- method getGenericReturnType -------- ");
Type genericReturnType = getPublicHa.getGenericReturnType();
System.out.println(genericReturnType);
// java.util.List<java.lang.String>
System.out.println("-------- method getParameterTypes -------- ");
Class<?>[] parameterTypes = getPublicHa.getParameterTypes();
for(Class<?> c : parameterTypes){
System.out.println(c);
}
//class java.lang.String
//class java.lang.String
//interface java.util.List
//interface java.util.List
System.out.println("-------- method getGenericParameterTypes -------- ");
Type[] genericParameterTypes = getPublicHa.getGenericParameterTypes();
for(Type t: genericParameterTypes){
System.out.println(t);
}
//class java.lang.String
//class java.lang.String
//java.util.List<java.lang.String>
//java.util.List<java.util.List<java.lang.String>>
System.out.println("-------- method getExceptionTypes -------- ");
Class<?>[] exceptionTypes = getPublicHa.getExceptionTypes();
for(Class<?> c : exceptionTypes){
System.out.println(c);
}
//class java.lang.Throwable
//class java.lang.NullPointerException
System.out.println("-------- method getGenericExceptionTypes -------- ");
Type[] genericExceptionTypes = getPublicHa.getGenericExceptionTypes();
for(Type t: genericExceptionTypes){
System.out.println(t);
}
// T
System.out.println("-------- method getGenericExceptionTypes -------- ");
Type[] genericExceptionTypes = getPublicHa.getGenericExceptionTypes();
for(Type t: genericExceptionTypes){
System.out.println(t);
}
// T
System.out.println("-------- method getTypeParameters -------- ");
TypeVariable<Method>[] typeParameters = getPublicHa.getTypeParameters();
for(TypeVariable<Method> typeVariable : typeParameters){
System.out.println(typeVariable);
}
// T
String invokeName = "name";
String invokeHhh = "hh";
List<String> invokeL = new ArrayList<>();
List<List<String>> invokeLl = new ArrayList<>();
getPublicHa.invoke(studyParam, invokeName , invokeHhh , invokeL , invokeLl);
// getPublicHa invoke process
}
}
Constructor
本次示例使用以下构造方法:
package com.study.pojo;
import lombok.*;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class StudyParam extends StudyParamParent implements StudyInfer {
String name;
List<String> list;
String[] strings;
List<List<String>> dList;
public StudyParam(String namePre, List<String> listPre, List<List<String>> dListPre, String name) {
super(namePre, listPre, dListPre);
this.name = name;
this.list = listPre;
this.dList = dListPre;
}
}
Constructor(构造方法) 与 Method 类似,Constructor 常用的方法如下: