反射是什么
反射: 将类的各个组成部分封装成其他对象
反射是框架实际的灵魂
框架: 半成品软件,可以在狂角点基础上进行软件开发
反射带来的好处
- 可以在程序运行过程中,操作这些对象
- 可以解耦
Java程序执行过程
拿一个People类说明
public class People {
//成员变量
private int age;
private String name;
//构造方法
public People(){}
//成员方法
public void say(){System.out.println(name+"say...");}
/**图片空间有限 下面的就不在图片标明了**/
public People(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
@Override
public String toString() {
return "People{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
下面用一张图来说明
- 源代码阶段:此时文件还处于硬盘中,并没有加载
- class类阶段:使用类加载器吧.class文件加载成一个class对象
- 运行时阶段:在创建对象的时候,将class里的内容封装成一个对象
获取class对象
class对象的获取方式有以下三种
- 使用
Class.forName("全类名");
- 类名.class
- 对象.getClass();
下面用代码来演示
public static void main(String[] args) throws Exception {
// 1. 使用`Class.forName("全类名");`
Class cls1 = Class.forName("test.People");
// 2. 类名.class
Class cls2 = People.class;
// 3. 对象.getClass();
People people = new People();
Class cls3 = people.getClass();
//输出3个对象
System.out.println(cls1);
System.out.println(cls2);
System.out.println(cls3);
//对比三个对象
System.out.println(cls3 == cls1);
System.out.println(cls2 == cls1);
System.out.println(cls3 == cls2);
}
输出结果
class test.People
class test.People
class test.People
true
true
true
由此可见 他们三种的获取的class对象 都是同一个对象
使用 Class对象
获取功能
下面说几种常见的功能
- 获取成员变量们
-
Field getField(String name)
返回一个public的指定名称的 Field对象。 -
Field[] getFields()
返回所有public的 Field对象数组。 -
Field getDeclaredField(String name)
返回一个指定名称的 Field对象。 -
Field[] getDeclaredFields()
返回所有 Field对象数组。
-
- 获取构造方法们
-
Constructor<T> getConstructor(Class<?>... parameterTypes)
返回一个指定public的 Constructor对象。 -
Constructor<?>[] getConstructors()
返回public的Constructor对象数组。 -
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
返回一个指定的 Constructor对象。 -
Constructor<?>[] getDeclaredConstructors()
返回所有Constructor对象。
-
- 获取成员方法们
Method getMethod(String name, Class<?>... parameterTypes)
返回一个指定的public的 Method 对象。Method[] getMethods()
返回所有public的 Method对象。Method getDeclaredMethod(String name, Class<?>... parameterTypes)
返回一个指定的 Method 对象。Method[] getDeclaredMethods()
返回所有 Method对象。
- 获取名称
String getName()
- 获取注解
-
<A extends Annotation> A getAnnotation(类<A> annotationClass)
返回指定类型的注解,如果没有返回null。 -
Annotation[] getAnnotations()
返回此元素上 存在的注释。
-
成员变量的修改和获取
- 获取值
get(Object obj)
- 设置值
set(Object obj,Object value)
- 暴力反射
setAccessible(true)
//获取public 修饰的
Field[] names = cls1.getFields();
for (Field name : names) {
System.out.println(name);
}
我们先来获取所有的变量,但是输出却一个也没有???
原来所有的变量都是private的
所以我们用第二种
//获取所有的变量
Field[] names = cls1.getDeclaredFields();
for (Field name : names) {
System.out.println(name);
}
下面输出结果,这个时候就有输出了
private int test.People.age
private java.lang.String test.People.name
我们也可以对变量进行修改
People p = new People();
p.setName("李四");
//获取name变量
Field field = cls1.getDeclaredField("name");
System.out.println(field.get(p));
虽然逻辑上看上去没有一点问题,但是程序一执行立即报错
报错的原因就是访问权限修饰符的安全检查
因为private是不允许被外界访问的
所以 这里需要暴力反射
在原来的代码上加上field.setAccessible(true);
People p = new People();
p.setName("李四");
//获取name变量
Field field = cls1.getDeclaredField("name");
//允许暴力反射
field.setAccessible(true);
System.out.println(field.get(p));//李四
field.set(p,"张三");
System.out.println(field.get(p));//张三
这样就可以对private变量进行修改和获取了
构造方法是使用和创建对象
- 创建对象方法
newInstance(Object...args)
- 暴力反射
setAccessible(true)
//获取构造器对象
Constructor wu_can = cls1.getConstructor();//无参构造
Constructor you_can = cls1.getConstructor(int.class, String.class);//有参数
//创建对象
Object p1 = wu_can.newInstance();
System.out.println(p1);
//修改信息
People zhang_san = (People) p1;//强制转换
zhang_san.setAge(25);
zhang_san.setName("张三");
System.out.println(p1);//和zhang_san是同一个对象
//使用有参数构造器创建对象
Object p2 = you_can.newInstance(20,"李四");
System.out.println(p2);
输出结果
People{age=0, name='null'}
People{age=25, name='张三'}
People{age=20, name='李四'}
成员方法的调用以及返回值的获取
- 执行方法
invoke(Object obj,Object...args)
返回返回值 - 暴力反射
setAccessible(true)
People p = new People(20,"张三");//执行对象
Object obj;//返回值
//调用say()
Method say = cls1.getMethod("say");
obj = say.invoke(p);//say()没有返回值
System.out.println("say-obj:"+obj);
//调用setName()
Method setName = cls1.getMethod("setName", String.class);
obj = setName.invoke(p,"李四");//setName没有返回值
System.out.println("setName-obj:"+obj);
//调用getName()
Method getName = cls1.getMethod("getName");
obj = getName.invoke(p);//这里有返回值
System.out.println("getName-obj:"+obj);
输出结果如下
张三say...
say-obj:null
setName-obj:null
getName-obj:李四