一:反射的理解
理解:Java 反射是可以让我们在运行时获取类的方法、属性、父类、接口等类的内部信息的机制。也就是说,反射本质上是一个“反着来”的过程。我们通过new创建一个类的实例时,实际上是由Java虚拟机根据这个类的Class对象在运行时构建出来的,而反射是通过一个类的Class对象来获取它的定义信息,从而我们可以访问到它的属性、方法,知道这个类的父类、实现了哪些接口等信息。
对象——>类——>调用里面的成员
反射的作用:
假如我们有两个程序员,一个程序员在写程序的时候,需要使用第二个程序员所写的类,但第二个程序员并没完成他所写的类。那么第一个程序员的代码能否通过编译呢?这是不能通过编译的。利用Java反射的机制,就可以让第一个程序员在没有得到第二个程序员所写的类的时候,来完成自身代码的编译。
二:主要功能,常用方法
功能:
* 在运行时判断任意一个对象所属的类;
* 在运行时构造任意一个类的对象;
* 在运行时判断任意一个类所具有的成员变量和方法;
* 在运行时调用任意一个对象的方法;
* 生成动态代理。
方法:
* Class类
* getFields()
* getDeclaredFields()
* getMethods()
* getDeclaredMethods()
* getDeclaredConstructors()
*
* getName()
* getSimpleName()
特点:
1.Class本身也是一个类
2.Class 对象只能由系统建立对象
3.一个类在 JVM 中只会有一个Class实例
4.一个Class对象对应的是一个加载到JVM中的一个.class文件
5.每个类的实例都会记得自己是由哪个 Class 实例所生成
6.通过Class可以完整地得到一个类中的完整结构
* Field类
* getModifiers():以int形式返回修饰符
* getType():获取Class类型的属性类型
* getName():获取属性名
*
* Method类
* getModifiers():以int形式返回修饰符
* getReturnType():获取Class类型的方法返回类型
* getName():获取方法名
* getParameterTypes():获取参数数组,类型Class[]
*
*
* Constructor类
* getModifiers():以int形式返回修饰符
* getName():获取构造器的全类名
* getParameterTypes():获取参数数组,类型Class[]
* Class:
* getField(String name):根据属性名获取属性对象(只能获取public修饰的,包含父类继承来的)
* getDeclaredField(String name):根据属性名获取属性对象(可以获取本类定义的所有的,不问修饰符)
* getMethod(String name,Class...class):根据方法名和参数列表获取方法对象(只能获取public修饰的,包含父类继承来的)
* getDeclaredMethod(String name,Class...class):根据方法名和参数列表获取方法对象(可以获取本类定义的所有的,不问修饰符)
*
*
* Field:
*
* set(对象,新值)
* get(对象)
* setAccessible(true)
*
* 注意:如果是静态属性,对象更改为null即可
*
* Method:
* invoke(对象,Object...obj)
* setAccessible(true)
getDeclaredFields 和 getFields 的区别:
getDeclaredFields()获得某个类的所有申明的字段,即包括public、private和proteced,但是不包括父类的申明字段。
getFields()获得某个类的所有的公共(public)的字段,包括父类。
Annotation
三个基本的Annotation:
–@Override:限定重写父类方法,该注释只能用于方法
–@Deprecated:用于表示某个程序元素(类,方法等)已过时
–@SuppressWarnings:抑制编译器警告.
三:反射的使用
创建
Class的三种方法
1. /**
2. * 获取Class对象的三种方式
3. * 1 Object ——> getClass();
4. * 2 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
5. * 3 通过Class类的静态方法:forName(String className)(常用)
6. *
7. */
8. public class Fanshe {
9. public static void main(String[] args) {
10. //第一种方式获取Class对象
11. Student stu1 = new Student();//这一new 产生一个Student对象,一个Class对象。
12. Class stuClass = stu1.getClass();//获取Class对象
13. System.out.println(stuClass.getName());
14.
15. //第二种方式获取Class对象
16. Class stuClass2 = Student.class;
17. System.out.println(stuClass == stuClass2);//判断第一种方式获取的Class对象和第二种方式获取的是否是同一个
18.
19. //第三种方式获取Class对象
20. try {
21. Class stuClass3 = Class.forName("fanshe.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
22. System.out.println(stuClass3 == stuClass2);//判断三种方式是否获取的是同一个Class对象
23. } catch (ClassNotFoundException e) {
24. e.printStackTrace();
25. }
26.
27. }
28. }
注意:在运行期间,一个类,只有一个Class对象产生。
三种方式常用第三种,第一种对象都有了还要反射干什么。第二种需要导入类的包,依赖太强,不导包就抛编译错误。一般都第三种,一个字符串可以传入也可写在配置文件中等多种方法。
通过反射获取类中的 三大主要成员:属性、方法、构造器
/**
* 功能:通过反射打印对应类中的所有属性
*
* @param c
* Class类的对象
*/
public static void printFields(Class c) {
// Field[] fields =
// c.getFields();//只能获取所有public修饰的属性,包含从父类继承来和自身定义,不限于直接父类
Field[] fields = c.getDeclaredFields();// 可以获取本类中定义的所有属性,不问修饰符
for (Field field : fields) {
// ①修饰符
int mod = field.getModifiers();
String modifier = Modifier.toString(mod);
// ②属性类型
String typeName = field.getType().getSimpleName();
// ③属性名
String name = field.getName();
System.out.println(modifier + "\t" + typeName + "\t" + name);
}
}
/**
* 功能:通过反射打印所有 的构造器
*
* @param c
*/
public static void printConstructors(Class c) {
Constructor[] constructors = c.getDeclaredConstructors();
for (Constructor constructor : constructors) {
// ①修饰符
String modifier = Modifier.toString(constructor.getModifiers());
// ②方法名
// String name = constructor.getName();//全类名
String name = c.getSimpleName();// 简单类名&构造器名
// ③参数列表
Class[] parameterTypes = constructor.getParameterTypes();
StringBuilder builder = new StringBuilder("(");
for (int i = 0; i < parameterTypes.length; i++) {
String simpleName = parameterTypes[i].getSimpleName();
builder.append(simpleName);
if (i == parameterTypes.length - 1)
continue;
builder.append(',');
}
builder.append(")");
System.out.println(modifier + "\t" + name + builder);
}
}
/**
* 功能:通过反射打印所有 的方法
*
* @param c
*/
public static void printMethods(Class c) {
// 步骤1:获取所有方法
// Method[] methods =
// c.getMethods();//只能获取所有public修饰的方法,包含从父类继承来的和自身定义的,不限于直接父类
Method[] methods = c.getDeclaredMethods();// 可以获取本类中定义的所有方法,不问修饰符
// 步骤2:遍历每个方法,打印每个方法签名的四要素
for (Method method : methods) {
// public void setAge(int,String)
// ①修饰符
String modifier = Modifier.toString(method.getModifiers());
// ②返回类型
String returnTypeName = method.getReturnType().getSimpleName();
// ③方法名
String name = method.getName();
// ④参数列表
Class[] parameterTypes = method.getParameterTypes();
StringBuilder builder = new StringBuilder("(");
for (int i = 0; i < parameterTypes.length; i++) {
String simpleName = parameterTypes[i].getSimpleName();
builder.append(simpleName);
if (i == parameterTypes.length - 1)
continue;
builder.append(',');
}
builder.append(")");
System.out.println(modifier + "\t" + returnTypeName + "\t" + name
+ builder);
}
}
通过反射访问属性和方法
// 访问方法
/*
* public void setAge(int age) { protected int getAge() {
*/
@Test
public void test2() throws Exception {
// 1.根据方法名和参数列表获取方法对象
// c.getMethod(name, parameterTypes) //只能获取public修饰的方法,包含从父类继承来的,不限于直接父类
Method method = c.getDeclaredMethod("getAge");// 获取本类中定义的所有方法,不问修饰符
method.setAccessible(true);
// 2.创建对象
// Object obj = c.newInstance();
// 3.调用方法
Object returnValue = method.invoke(null);
System.out.println("返回值:" + returnValue);
}
// 访问属性
@Test
public void test1() throws Exception {
// 1.根据属性名获取属性对象
// Field filed = c.getField(name); //只能获取public修饰的属性,包含从父类继承来的,不限于直接父类
Field field = c.getDeclaredField("name");
field.setAccessible(true);
// 2.获取对应类的对象
Object obj = c.newInstance();
// 3.为属性赋值
field.set(obj, "慕容复");
// 4.读取属性
Object value = field.get(obj);
System.out.println(value);
// -----------------------练习------------------
System.out.println(field.get(c.newInstance()));
}
// 访问静态属性
@Test
public void exec1() throws Exception {
// 1.根据属性名获取属性对象
Field field = c.getDeclaredField("SCHOOL");
// 2.暴破
field.setAccessible(true);
// 3.为属性赋值
// field.set(null, "北京大学");
// 4.访问属性
System.out.println(field.get(null));
}