一、反射概述
1、什么是反射?
将类的各个组成部分封装为其他对象,这就是反射机制。
我们来看一下java代码在计算机中经历的三个阶段。
将类的成员变量封装为Filed对象,将类的构造方法封装Constructor对象,将成员方法封装为Method对象。
2、反射有什么好处呢?
- 可以在程序运行过程中,操作这些对象。
举个例子:我们创建一个对象(比如String)时,当输入对象名.的时候,出现一大堆方法提示,那么这些方法从哪来呢?其实它内部用的就是反射机制。我们定义了一个字符串,则会将字符串的字节码文件加载进内存,在内存中,有一个Class类对象,Class类对象将String类的所有方法抽取出来封装成Method对象,然后将所有方法放到一个Method[]数组中,然后将其方法展示在列表中。(见下图)
- 可以解耦,提高程序的可扩展性。
二、反射_获取字节码Class类对象
获取Class对象的方式有三种,分别对应java代码经历的三个阶段。
1、Class.forName("全类名“):将字节码文件加载进内存,返回Class对象。
多用于配置文件,将类名定义在配置文件中。读取文件,加载类。
2、类名.class():通过类名的属性class获取。
多用于参数的传递。
3、对象.getClass():etClass()方法在Object类中定义。
多用于对象的获取字节码方式。
代码:
public static void main(String[] args) throws ClassNotFoundException {
// 1、全类名
Class cls1 = Class.forName("cn.reflect.Person");
System.out.println(cls1);
// 2、类名.class
Class cls2 = Person.class;
System.out.println(cls2);
// 3、对象.getclass()
Person person = new Person();
Class cls3 = person.getClass();
System.out.println(cls3);
System.out.println(cls1 == cls2);//输出true
System.out.println(cls2 == cls3);//输出true
}
结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。
三、反射_Class对象功能
Class获取常用对象功能
带declared不考虑修饰符,不带declared的只用获取public修饰的。
1、获取Filed
Field[] getFields():获取所有public修饰的成员变量
Field getField(String name) 获取指定名称的public修饰的成员变量
Filed[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
Filed[] getDeclaredFields(String name) 获取指定的成员变量,不考虑修饰符
2、获取Constructor
Constructor<?>[] getConstuctors()
Constructor getConstructor(类<?>…parameterTypes)
Constructor<?>[] getDeclaredConstuctors()
Constructor getDeclaredConstructor(类<?>…parameterTypes)
3、获取Method
Method[] getMethods():
Method[] getMethod(String name,类<?>…parameterTypes)
Method[] getDeclaredMethods():
Method[] getDeclaredMethod(String name,类<?>…parameterTypes)
4、获取类名
String getName();
1、获取成员变量
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException {
// 获取Class类对象
Class personClass = Person.class;
System.out.println(personClass);
/*
Field[] getFields():获取所有public修饰的成员变量
Field getField(String name) 获取指定名称的public修饰的成员变量
Filed[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
Filed[] getDeclaredFields(String name) 获取指定的成员变量,不考虑修饰
*/
// 获取所有Public修饰的成员变量
Field[] fields = personClass.getFields();
for (Field field : fields)
System.out.println(field);
// 获取指定名称的成员变量,name必须是public修饰的
Field a = personClass.getField("name");
// 获取成员变量a的值
Person per = new Person();
Object value = a.get(per);
System.out.println(value);
// 设置a的值
a.set(per, "Casey");
System.out.println(per);
// Field[] getDeclaredFields();获取所有成员变量,不考虑修饰符
Field[] declaredFields = personClass.getDeclaredFields();
for (Field dField : declaredFields)
System.out.println(dField);
Field d = personClass.getDeclaredField("id");
// 忽略访问全权限修饰符的安全检查
d.setAccessible(true);// 暴力反射
Object value1 = d.get(per);
System.out.println(value1);
}
2、获取构造方法
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// 获取Class类对象
Class personClass = Person.class;
/*
Constructor<?>[] getConstuctors()
Constructor<T> getConstructor(类<?>...parameterTypes)
Constructor<?>[] getDeclaredConstuctors()
Constructor<T> getDeclaredConstructor(类<?>...parameterTypes)
*/
// 获取构造方法,带有一个int 型的参数
Constructor constructor = personClass.getConstructor(int.class);
constructor.setAccessible(true);
System.out.println(constructor);
// 创建对象
Object per = constructor.newInstance(123);
System.out.println(per);
//空参构造
Constructor constructor1 = personClass.getConstructor();
constructor1.setAccessible(true);
System.out.println(constructor1);
// 创建对象
Object per1 = constructor1.newInstance(123);
System.out.println(per1);
//空参构造可以简化
Object per2 = personClass.newInstance();
System.out.println(per2);
}
3、获取成员方法
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
Class personClass = Person.class;
/*
* public修饰的方法 Method[] getMethods(): Method[] getMethod(String
* name,类<?>...parameterTypes)
*
* 不考虑修饰符 Method[] getDeclaredMethods(): Method[]
* getDeclaredMethod(String name,类<?>...parameterTypes)
*/
// 获取指定名称的方法
Method eat = personClass.getMethod("eat");
Person p = new Person();
// 执行方法
eat.invoke(p);
// 获取带有参数的方法
Method eat1 = personClass.getMethod("eat", String.class);
eat1.invoke(p, "food");
// 获取所有public方法,包括object中的public方法
Method[] methods = personClass.getMethods();
for (Method m : methods) {
m.setAccessible(true);// 暴力反射,私有的也能被访问
System.out.println(m);
}
// 获取类里面所有方法
Method[] methods1 = personClass.getDeclaredMethods();
for (Method m : methods1) {
m.setAccessible(true);// 暴力反射
System.out.println(m);
}
}
4、获取类名
//获取类名
String className = personClass.getName();
System.out.println(className);