1 Java反射基础
1.1 获得 Class 对象的三种方法
Class.forName()
类.class
对象.getClass()
(1)使用 Class 类的 forName 静态方法:
public static Class<?> forName(String className)
比如在 JDBC 开发中常用此方法加载数据库驱动
Class.forName(driver);
(2)直接获取某一个对象的 class,比如:
Class<?> klass = int.class;
Class<?> classInt = Integer.TYPE;
(3)调用某个对象的 getClass() 方法,比如:
StringBuilder str = new StringBuilder("123");
Class<?> klass = str.getClass();
1.2 创建实例
(1)使用Class对象的newInstance()方法
Class<?> c = String.class;
Object str = c.newInstance();
(2)先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。
//获取String所对应的Class对象
Class<?> c = String.class;
//获取String类带一个String参数的构造器
Constructor constructor = c.getConstructor(String.class);
//根据构造器创建实例
Object obj = constructor.newInstance("23333");
System.out.println(obj);
1.3 获取属性
getFiled:访问公有的成员变量
getDeclaredField:所有已声明的成员变量,但不能得到其父类的成员变量
getFileds 和 getDeclaredFields 方法用法同上(参照 Method)。
1.4 获取方法
(1)getDeclaredMethods 方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
public Method[] getDeclaredMethods() throws SecurityException
(2)getMethods 方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。
public Method[] getMethods() throws SecurityException
(3)getMethod 方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象。
public Method getMethod(String name, Class<?>... parameterTypes)
当我们从类中获取了一个方法后,我们就可以用 invoke() 方法来调用这个方法
Class<?> klass = methodClass.class;
//创建methodClass的实例
Object obj = klass.newInstance();
//获取methodClass类的add方法
Method method = klass.getMethod("add",int.class,int.class);
//调用method对应的方法 => add(1,4)
Object result = method.invoke(obj,1,4);
1.5 获取构造器
通过Class类的getConstructor方法得到Constructor类的一个实例,而Constructor类有一个newInstance方法可以创建一个对象实例
1.6 判断是否是某个类的实例
一般地,我们用 instanceof 关键字来判断是否为某个类的实例。同时我们也可以借助反射中 Class 对象的 isInstance() 方法来判断是否为某个类的实例
注意:
1.getFields和getDeclaredFields的区别:
getFields:获取当前类的public变量和父类public变量
getDeclaredFields:获取当前类的所有变量,但不会获取父类变量
2.getMethods和getDeclaredMethods的区别:
getMethods:获取当前类的public方法和父类public方法。注意所有类都继承自Object,所以也会获取Object类的public方法。
getDeclaredMethods:获取当前类的所有方法,但不会获取父类方法。
学一学,练一练
(代码来源:https://juejin.im/post/598ea9116fb9a03c335a99a4)
public class FatherClass {
public String mFatherName;
public int mFatherAge;
public void printFatherMsg(){}
}
public class SonClass extends FatherClass{
private String mSonName;
protected int mSonAge;
public String mSonBirthday;
public void printSonMsg(){
System.out.println("Son Msg - name : "
+ mSonName + "; age : " + mSonAge);
}
private void setSonName(String name){
mSonName = name;
}
private void setSonAge(int age){
mSonAge = age;
}
private int getSonAge(){
return mSonAge;
}
private String getSonName(){
return mSonName;
}
}
/**
* @Description TODO
* @Author lilong
* @Date 2018-11-14 11:43
*/
public class Main {
public static void main(String[] args) {
printFields();
System.out.println("###################################");
printMethods();
}
/**
* 通过反射获取类的所有变量
*/
private static void printFields(){
//1.获取并输出类的名称
Class mClass = SonClass.class;
System.out.println("类的名称:" + mClass.getName());
//2.1 获取所有 public 访问权限的变量
// 包括本类声明的和从父类继承的
Field[] fields = mClass.getFields();
//2.2 获取所有本类声明的变量(不问访问权限)
//Field[] fields = mClass.getDeclaredFields();
//3. 遍历变量并输出变量信息
for (Field field : fields) {
//获取访问权限并输出
int modifiers = field.getModifiers();
System.out.print(Modifier.toString(modifiers) + " ");
//输出变量的类型及变量名
System.out.println(field.getType().getName() + " " + field.getName());
}
}
/**
* 通过反射获取类的所有方法
*/
private static void printMethods(){
//1.获取并输出类的名称
Class mClass = SonClass.class;
System.out.println("类的名称:" + mClass.getName());
//2.1 获取所有 public 访问权限的方法
//包括自己声明和从父类继承的
Method[] mMethods = mClass.getDeclaredMethods();
//2.2 获取所有本类的的方法(不问访问权限)
//Method[] mMethods = mClass.getDeclaredMethods();
//3.遍历所有方法
for (Method method : mMethods) {
//获取并输出方法的访问权限(Modifiers:修饰符)
int modifiers = method.getModifiers();
System.out.print(Modifier.toString(modifiers) + " ");
//获取并输出方法的返回值类型
Class returnType = method.getReturnType();
System.out.print(returnType.getName() + " " + method.getName() + "( ");
//获取并输出方法的所有参数
Parameter[] parameters = method.getParameters();
for (Parameter parameter: parameters) {
System.out.print(parameter.getType().getName() + " " + parameter.getName() + ",");
}
//获取并输出方法抛出的异常
Class[] exceptionTypes = method.getExceptionTypes();
if (exceptionTypes.length == 0) {
System.out.println(" )");
}
else {
for (Class c : exceptionTypes) {
System.out.println(" ) throws " + c.getName());
}
}
}
}
}
运行下看看:
2 ReflectionUtils
1)查找指定的属性
Field findField(Class<?> clazz, String name, Class<?> type)
name:字段名,type:字段类型。类型可以不带。
2)查找指定的方法
Method findMethod(Class<?> clazz, String name, Class<?>... paramTypes)
name:方法名,paramTypes:参数类型,可不带
3)调用目标方法
Object invokeMethod(Method method, Object target, Object... args)
args可不带
学一学,练一练
public class SuperClass {
private String fatherPrivate = "privateField爹也不太懂";
protected String fatherProtected = "protectedField爹也不太懂";
public String fatherPublic = "publicField爹也不太懂";
private void fatherPrivateMethod(){
System.out.println("父类private方法");
}
private void fatherProtectedMethod(){
System.out.println("父类protected方法");
}
private void fatherPublicMethod(){
System.out.println("父类public方法");
}
}
public class SubClass extends SuperClass{
private String privateField = "privateField大头儿子";
protected String protectedField = "protectedField大头儿子";
public String publicField = "publicField大头儿子";
private void privateMethod() {
System.out.println("子类private方法");
}
protected void protectedMethod() {
System.out.println("子类protected方法");
}
public void publicMethod() {
System.out.println("子类public方法");
}
public String getPrivateField() {
return privateField;
}
public void setPrivateField(String privateField) {
this.privateField = privateField;
}
public String getProtectedField() {
return protectedField;
}
public void setProtectedField(String protectedField) {
this.protectedField = protectedField;
}
public String getPublicField() {
return publicField;
}
public void setPublicField(String publicField) {
this.publicField = publicField;
}
}
public class Main {
public static void main(String[] args) {
//获取属性值
getAndPrintField("privateField");
getAndPrintField("protectedField");
getAndPrintField("publicField");
System.out.println();
//获取父类中的属性
getAndPrintField("fatherPrivate");
getAndPrintField("fatherProtected");
getAndPrintField("fatherPublic");
System.out.println();
//获取方法
getAndPrintMethod("privateMethod");
getAndPrintMethod("protectedMethod");
getAndPrintMethod("publicMethod");
System.out.println();
//获取父类方法
getAndPrintMethod("fatherPrivateMethod");
getAndPrintMethod("fatherProtectedMethod");
getAndPrintMethod("fatherPublicMethod");
}
private static void getAndPrintField(String filedName) {
SubClass test = new SubClass();
//获取属性
Field field = ReflectionUtils.findField(test.getClass(), filedName, String.class);
//赋权限,否则会抛IllegalStateException
ReflectionUtils.makeAccessible(field);
String val = (String)ReflectionUtils.getField(field, test);
System.out.println(val);
}
private static void getAndPrintMethod(String methodName){
SubClass test = new SubClass();
Method method = ReflectionUtils.findMethod(test.getClass(), methodName);
ReflectionUtils.makeAccessible(method);
ReflectionUtils.invokeMethod(method, test);
}
}
运行下看看:
嗯,可以获取所有变量、方法,包括父类的。
3 反射的应用
Spring、MyBatis、Dubbo都大量使用了反射,例如Spring会根据xml中配置的beanName获取到Bean就用的反射。
后面再专门写博客介绍反射的应用吧。
还有一个用处是写单测的时候,可能方法是private的,这个时候我们可以用反射调用这个方法:
public class TestClass {
private String MSG = "Original";
private void privateMethod(String head , int tail){
System.out.print(head + tail);
}
public String getMsg(){
return MSG;
}
}
public class UnitTest {
public static void main(String[] args) {
try {
TestClass testClass = new TestClass();
Method method = TestClass.class.getDeclaredMethod("privateMethod", String.class, int.class);
method.setAccessible(true);
method.invoke(testClass, "我是头", 666);
} catch (Exception e) {
e.printStackTrace();
}
}
}
跑跑看: