反射
反射是什么,能干什么
反射是:指程序可以访问、检测和修改它本身状态或行为的一种能力
反射是一种能力,所以给的定义就是说明了它能干嘛。
我们平时用反射主要做:
获取类型的相关信息
动态调用方法
动态构造对象
从程序集中获得类型。
一、Class类
- 在面对对象编程中,万事万物皆对象,但是类本身又是谁的对象呢?
他是java.lang.Class的对象 - 获取类类型的3种方法
- 通过对象类的对象获取
Foo foo = new Foo();
Class class1 = foo.getClass();
- 通过类名获取
Class class2 = Foo.class;
- 还是通过类名获取,但是要try catch, 并且要转换类型
try {
Class class3 = (Class) Class.forName("Foo");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
二、获取类的方法信息
- 一个成员方法就是Method类的对象
- getMethods()是获得该类的所有public方法,包括从父类继承来的方法
Method[] methods1 = class1.getMethods();
- getDeclaredMethods()是获取当前类自己声明的成员方法,不包含父类继承来的,但是不问访问权限
Method[] methods2 = class1.getDeclaredMethods();
- 得到返回值类型,先得到返回值类型的类类型,再获得名字
Class returnType = methods1[i].getReturnType();
String returnTypeName = returnType.getName();
- 得到方法名
for (int i = 0; i < methods1.length; i++) {
System.out.println(methods1[i].getName());
}
- 得到参数类型,因为参数可能有多个,所以先得到参数列表,再遍历它得到参数类型的名字
Class[] paramTypes = methods1[i].getParameterTypes();
for (Class paramType : paramTypes) {
String paramTypeName = paramType.getName();
}
三、获取成员变量的信息
- 成员变量是java.lang.reflect.Field类的对象
- getFields()获得的是所有public的成员变量
Field[] fields1 = class1.getFields();
- getDeclaredFields()获得的是自己声明的所有的成员变量
Field[] fields2 = class1.getDeclaredFields();
- 获得成员变量类型的名称
for (Field field : fields2) {
Class fieldType = field.getType();
String fieldTypeName = fieldType.getName();
}
- 获得成员变量名称
String fieldName = field.getName();
四、获取构造函数的信息
- 构造函数是java.lang.reflect.Constructor的对象
- 获得构造函数,方法基本同上
Constructor[] constructors1 = class1.getConstructors();
Constructor[] constructors2 = class1.getDeclaredConstructors();
- 获得构造参数类型
for (Constructor constructor : constructors2) {
Class[] paramTypes = constructor.getParameterTypes();
for (Class paramType : paramTypes) {
String paramTypeName = paramType.getName();
}
}
- 获得构造方法名称
String csName = constructor.getName();
五、 反射调用方法
public class A {
public void print(int a, int b) {
System.out.println(a + b);
}
public void print(String a, String b) {
System.out.println(a.toUpperCase() + b.toLowerCase());
}
}
- 获取方法对象,先获得类类型,再操作
A a1 = new A();
Class clazz = a1.getClass();
// 这里第一个参数表示方法名,后面的是参数的类类型,如果没参数,就不传
// 要唯一确定一个方法,就得确定他的方法名和参数类型
Method m = clazz.getMethod("print", int.class, int.class);
- 反射调用方法
// 这里是方法对象调用invoke方法,第一个参数是对象,后面的是参数,没参数就不写
//普通调用方法为:a1.print(10,20);
m.invoke(a1, 10, 20);
下面直接上代码
首先建立一个对象
Stu.java
package com.hqyj.pojo;
public class Stu {
public String name;
private int id;
private String sex;
private void sleep(String name) {
System.out.println("我和"+name+"睡觉,你别管");
}
/**
*
* <p>
* 1、为什么这个方法过时了
* 2、推荐我使用哪个类来使用
* </p>
* @author HC
* @Date 2018年12月14日
*/
@Deprecated
public void eat() {
System.out.println("吃饭");
}
public void project(String project) {
System.out.println("正在学习:"+project);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Stu [name=" + name + ", id=" + id + ", sex=" + sex + "]";
}
public Stu() {
super();
// TODO Auto-generated constructor stub
}
}
测试类,ReflectDemo.java
package com.hqyj.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import com.hqyj.pojo.Stu;
public class ReflectDemo {
public static void main(String[] args) {
Class<Stu> stuClazz = getStuClazz();
Field field = getField(stuClazz);
System.out.println("***************");
Method method =getStuMethod(stuClazz);
System.out.println("***************");
//普通的调用方法
Stu stu = new Stu();
stu.project("springboot");
System.out.println("***************");
//反射调用方法
try {
//让私有的方法能被访问
method.setAccessible(true);
method.invoke(stuClazz.newInstance(),"李万杰");
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static Method getStuMethod(Class<Stu> stuClazz) {
/**
* 获得方法
* 1、获得所有方法
* 2、获得指定方法
*/
//所有public的方法
System.out.println("获取所有public方法");
Method[] methods = stuClazz.getMethods();
for (Method method : methods) {
String returnType = method.getReturnType().getName();
String methodName = method.getName();
String str = returnType +":"+methodName+"(";
/*Parameter[] parameters = method.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}*/
Class<?>[] clazzes = method.getParameterTypes();
for (Class clazz : clazzes) {
str+=clazz.getName()+", ";
}
str +=")";
System.out.println(str);
}
System.out.println("***************");
//获得所有方法
System.out.println("获取所有方法");
Method[] methods2 = stuClazz.getDeclaredMethods();
for (Method method : methods2) {
String returnType = method.getReturnType().getName();
String methodName = method.getName();
String str = returnType +":"+methodName+"(";
/*Parameter[] parameters = method.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}*/
Class<?>[] clazzes = method.getParameterTypes();
for (Class clazz : clazzes) {
str+=clazz.getName()+", ";
}
str +=")";
System.out.println(str);
}
System.out.println("***************");
//获得指定方法
System.out.println("获取指定方法");
try {
Method method = stuClazz.getDeclaredMethod("sleep",String.class);
System.out.println(method);
return method;
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
private static Field getField(Class<Stu> stuClazz) {
/**
* 获得字段
* 1、获取所有字段
* 2、获取指定字段
*/
//获取所有的(包括从父类继承下来的)public字段
Field[] fields = stuClazz.getFields();
System.out.println("获取所有的(包括从父类继承下来的)public字段");
for (Field field : fields) {
System.out.println(field.getType()+":"+field.getName());
}
//获取所有的字段,不管访问权限
Field[] fields2 = stuClazz.getDeclaredFields();
System.out.println("获取所有的字段,不管访问权限");
for (Field field : fields2) {
System.out.println(field.getType()+":"+field.getName());
}
//获取指定字段
try {
Field field = stuClazz.getDeclaredField("name");
System.out.println("获取指定字段");
System.out.println(field.getType()+":"+field.getName());
return field;
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/**
*
* <p>
* 获取类类型
* </p>
* @author HC
* @Date 2018年12月14日
* @return
*/
private static Class<Stu> getStuClazz(){
Stu stu = new Stu();
Class<? extends Stu> stuClazz = stu.getClass();
Class<Stu> stuClazz2 = Stu.class;
try {
Class<?> stuClazz3 = Class.forName("com.hqyj.pojo.Stu");
}catch( ClassNotFoundException e ) {
e.printStackTrace();
}
return stuClazz2;
}
}
结果:
获取所有的(包括从父类继承下来的)public字段
class java.lang.String:name
获取所有的字段,不管访问权限
class java.lang.String:name
int:id
class java.lang.String:sex
获取指定字段
class java.lang.String:name
***************
获取所有public方法
java.lang.String:toString()
java.lang.String:getName()
int:getId()
void:setName(java.lang.String, )
void:setId(int, )
void:setSex(java.lang.String, )
void:project(java.lang.String, )
void:eat()
java.lang.String:getSex()
void:wait()
void:wait(long, int, )
void:wait(long, )
boolean:equals(java.lang.Object, )
int:hashCode()
java.lang.Class:getClass()
void:notify()
void:notifyAll()
***************
获取所有方法
java.lang.String:toString()
java.lang.String:getName()
int:getId()
void:setName(java.lang.String, )
void:sleep(java.lang.String, )
void:setId(int, )
void:setSex(java.lang.String, )
void:project(java.lang.String, )
void:eat()
java.lang.String:getSex()
***************
获取指定方法
private void com.hqyj.pojo.Stu.sleep(java.lang.String)
***************
正在学习:springboot
***************
我和李万杰睡觉,你别管
List绕过编译添加元素
package com.hqyj.reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import com.hqyj.pojo.Stu;
public class ArrayListDemo {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
ArrayList<Integer> intList= new ArrayList<>();
ArrayList<String> stringList= new ArrayList<>();
Class class1 = intList.getClass();
Class class2 = stringList.getClass();
//结果为true,说明泛型只是在编译时检查,在运行时是去掉泛型的
System.out.println(class1 == class2);
//获取指定方法
Method add = class1.getDeclaredMethod("add",Object.class);
//反射调用方法
add.invoke(intList, "haha");
add.invoke(intList, new Stu());
System.out.println(intList);
}
}
结果:
true
[haha, Stu [name=null, id=0, sex=null]]
总结
//获得Class的方法
//第一种
MyClazz myClazz = new MyClazz();
Class<? extends MyClazz> myClass2 = myClazz.getClass();
//第二种
Class myClass3 = MyClazz.class;
//第三种
Class myClass4 = Class.forName("MyClazz");
//获得所有public包括父类字段
Field[] fields = myClass.getFields();
//获得所有字段,不管访问权限
Field[] fields2 = myClass.getDeclaredFields();
//获得指定字段
Field field3 = myClass.getDeclaredField("字段名");
//获得所有public包括父类方法
Method[] methods = myClass.getMethods();
//获得所有方法,不管访问权限
Method[] methods2 = myClass.getDeclaredMethods();
//获得指定方法
Method method3 = myClass.getDeclaredMethod("方法名");
//调用方法(第一个参数,第二个参数类型)
method3.invoke("参数", Object.class);