目录
(1)Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到类对象之后,再通过类对象进行反编译,从而获取对象的各种信息。
(2)Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁
反射:能够分析类信息的能力叫做反射,那什么是类的信息?
简单的来说比如 属性、方法、构造器等等。。。
- Class class1 = Class.forName("reflect.Person");
- System.out.println(class1);
- Field[] fields = class1.getFields();
- for (Field field : fields) {
- System.out.println(field);
- }
那么一个新的问题就来了,我们明明可以通过new 一个对象来获取类信息,那么我们为什么要使用反射呢?
我们在这里说一个实际的列子,比如说我们使用的servlet,在servlet当中我们用过jdbc操作,在这个类当中我们引入了一个mysql.jar包,那么这个jar包是怎么起作用的呢,请大家注意,我们的servlet类当中没有main方法,那我们的servlet类是如何启动的呢?如何加载到我们的JVM当中呢?
答案就是使用了反射,大家看一个东西
从上面可以看到,正是因为有了反射,我们才能将他们加载如JVM当中。
那么反射是如何工作的呢?
要想理解反射是如何工作的我们先来看类的生命周期
1.在程序的运行过程中,来操作这些对象
- String str = "123";
- str.
我们对 . 出很多的方法,这其实就是内部使用的是反射机制,你定义了一个字符串,那么他会把字符串的字节码文件加载进内存,在内存当中有一个class类对象,class对象已将所有的方法都抽取出来封装在method[]数组当中,所以我们能够 . 出这么多的程序。
2.可以解耦,提高程序的可扩展性
获取class对象的方式
1.Class.forName("全类名"):将字节码文件加载进内存,返回class对象
多用于配置文件,将类名定义在配置文件当中,读取文件,加载类
2.类名.class: 通过类名的class获取
多用于参数的传递
3.对象.getClass() :getClass()方法在object类当中定义着
多用于对象获取字节码的方式
首先定义一个person类,内部定义好成员变量,构造方法和成员方法
- public class Person {
-
- private String nameString;
- private int age;
-
- public Person() {
-
- }
-
- public Person(String nameString, int age) {
- this.nameString = nameString;
- this.age = age;
- }
-
- public String getNameString() {
- return nameString;
- }
-
- public void setNameString(String nameString) {
- this.nameString = nameString;
- }
-
- public int getAge() {
- return age;
- }
-
- public void setAge(int age) {
- this.age = age;
- }
-
- @Override
- public String toString() {
- return "Person [nameString=" + nameString + ", age=" + age + "]";
- }
-
- }
定义测试类
- public class refulectDemo1 {
-
- /**
- * 1.Class.forName("全类名"):将字节码文件加载进内存,返回class对象
- 2.类名.class:通过类名的class获取
- 3.对象.getClass(): getClass()方法在object类当中定义着
- * @throws ClassNotFoundException
- */
- public static void main(String[] args) throws Exception {
- // 1.Class.forName("全类名"):
- Class class1 = Class.forName("reflect.Person");
- System.out.println(class1);
-
- //2.类名.class:通过类名的class获取
- Class class2 = Person.class;
- System.out.println(class2);
-
- //3.对象.getClass()
- Person person = new Person();
- Class class3 = person.getClass();
- System.out.println(class3);
-
- }
-
- }
用 == 进行比较
- System.out.println(class1 == class2);
- System.out.println(class2 == class3);
输出为:
- true
- true
结论:
同一个类加载器加载的文件(*.class)在一次程序运行过程中,只会被加载一次,不论你通过那种方式获取的class对象都是同一个
class对象常用功能
- /*通过反射获取Person类对象*/
- Class aClass = Class.forName("com.qcby.reflect.Person");
-
- Field[] fields = aClass.getDeclaredFields();
- System.out.println("获取Person的所有属性对象");
- for (Field field : fields) {
- System.out.println(field);
- }
- System.out.println("获取Person的age属性对象");
- Field age = aClass.getDeclaredField("age");
- System.out.println(age);
- System.out.println("-------------------------------------\n");
-
-
- Constructor[] constructors = aClass.getDeclaredConstructors();
- System.out.println("获取Person的所有构造方法");
- for (Constructor constructor : constructors) {
- System.out.println(constructor);
- }
- System.out.println("获取Person的无参构造方法");
- Constructor constructor = aClass.getDeclaredConstructor();
- System.out.println(constructor);
- System.out.println("获取Person的有参构造方法");
- Constructor constructor1 = aClass.getDeclaredConstructor(String.class,Integer.class);
- System.out.println(constructor1);
- System.out.println("-------------------------------------\n");
-
- Method[] declaredMethods = aClass.getDeclaredMethods();
- System.out.println("获取Person的所有普通方法");
- for (Method declaredMethod : declaredMethods) {
- System.out.println(declaredMethod);
- }
- System.out.println("获取Person的getAge普通方法");
- Method getAge = aClass.getDeclaredMethod("getAge");
- System.out.println(getAge);
- System.out.println("获取Person的getAge普通方法");
- Method setAge = aClass.getDeclaredMethod("setAge",Integer.class);
- System.out.println(setAge);
- System.out.println("-------------------------------------\n");
-
- System.out.println("获取Person的全类名");
- System.out.println(aClass.getName());
- System.out.println("获取Person的类名");
- System.out.println(aClass.getSimpleName());
Field成员变量
操作
1.设置值
void set(Object obj,Object value)
2.获取值
get(Object obj)
- public static void main(String[] args) throws Exception {
-
- //0.获取Person的Class对象
- Class personClass = Person.class;
- /*
- 1. 获取成员变量们
- * Field[] getFields()
- * Field getField(String name)
- * Field[] getDeclaredFields()
- * Field getDeclaredField(String name)
- */
- //1.Field[] getFields()获取所有public修饰的成员变量
- Field[] fields = personClass.getFields();
- for (Field field : fields) {
- System.out.println(field);
- }
-
- System.out.println("------------");
- //2.Field getField(String name)
- Field a = personClass.getField("a");
- //获取成员变量a 的值
- Person p = new Person();
- Object value = a.get(p);
- System.out.println(value);
- //设置a的值
- a.set(p,"张三");
- System.out.println(p);
-
- System.out.println("===================");
-
- //Field[] getDeclaredFields():获取所有的成员变量,不考虑修饰符
- Field[] declaredFields = personClass.getDeclaredFields();
- for (Field declaredField : declaredFields) {
- System.out.println(declaredField);
- }
- //Field getDeclaredField(String name)
- Field d = personClass.getDeclaredField("d");
- //忽略访问权限修饰符的安全检查
- d.setAccessible(true);//暴力反射
- Object value2 = d.get(p);
- System.out.println(value2);
-
- }
忽略安全访问修饰符的安全检查 setAccessible(true) //暴力反射 ---》private
Constructor访问构造方法
*创建对象
*T newInstance(Object... initarges)
*如果使用空参数构造方法,此操作可以简化:class对象的newInstance方法
- public static void main(String[] args) throws Exception {
- //0.获取Person的class对象
- Class personClass = Person.class;
-
- //因为构造器的方法名称是相同的,不同的是参数列表,所以我们可以根据不同的参数列表来找到构造器
- Constructor constructor = personClass.getConstructor(String.class,int.class);
- System.out.println(constructor);
- //创建对象
- Object perObject = constructor.newInstance("张三",20);
- System.out.println(perObject);
-
- System.out.println("-------------------------------");
-
- Constructor constructor1 = personClass.getConstructor();
- System.out.println(constructor1);
- //创建对象
- Object perObject1 = constructor1.newInstance();
- System.out.println(perObject1);
-
- System.out.println("-------------------------------");
- Object o = personClass.newInstance();
- System.out.println(o);
- }
Method:方法对象
*执行方法
*object invoke(Object object,Object... ages)
*获取方法名称
*String getName:获取方法名
- public static void main(String[] args) throws Exception {
- //0.获取Person的class对象
- Class personClass = Person.class;
-
- //获取指定名称的方法,方法无参
- Method eat_method = personClass.getMethod("eat");
- //执行方法
- Person person =new Person();
- eat_method.invoke(person);
-
- //获取指定名称的方法,方法有参
- Method eat_method1 = personClass.getMethod("eat",String.class);
- //执行方法
- eat_method1.invoke(person,"饭");
-
- //获取所有public修饰的方法
- Method[] methods = personClass.getMethods();
- for (Method method : methods) {
- System.out.println(method);
- //获取方法的名称
- String name = method.getName();
- System.out.println(name);
- }
- }
java bean是java类的一种特殊格式,java bean要求
1.该类下所有的成员变量都是私有的
2..每一个私有的变量都有一对方法对他进行操作,分别是get()和set()方法
3.在set方法当中有一个给成员变量赋值的方法
作业:给定一个java bean,获取该类的构造方法来构造对象,获取该类的名称和该类中每一个变量的名称和方法的名称,并执行相关方法。给每一个变量赋值,并获取值,执行每一个构造方法,执行相应的方法
- public class Student {
-
- private String name;
- private int age;
- private String address;
- public Student(String name,int age,String address) {
- this.address = address;
- this.age = age;
- this.name = name;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public String getAddress() {
- return address;
- }
- public void setAddress(String address) {
- this.address = address;
- }
- }
- public class CommonReflect {
-
- //获取该类的名称
- public static void getClassName(Object object) {
- String className = object.getClass().getSimpleName();
- System.out.println("类的名字是:"+className);
- }
-
- //获取类的变量名称
- public static void getField(Object object) {
- Field[] fields = object.getClass().getDeclaredFields();
- for (int i = 0; i < fields.length; i++) {
- System.out.println("成员变量的名称为:"+fields[i].getName());
- }
- }
-
- //获取类的成员方法
- public static void getMethod(Object object) {
- Method[] methods = object.getClass().getDeclaredMethods();
- for (int i = 0; i < methods.length; i++) {
- System.out.println("成员方法的名称:"+methods[i].getName());
- }
- }
-
- //调用该类的成员方法,以get为例
- public static void getAction(Object object) throws Exception {
- //获取到有多少get方法
- Field[] fields = object.getClass().getDeclaredFields();
- for (int i = 0; i < fields.length; i++) {
- String fieldName = fields[i].getName();
- String fistfont = fieldName.substring(0,1).toUpperCase();
- String methodname = "get"+fistfont+fieldName.substring(1);
- Method method = object.getClass().getMethod(methodname);
- System.out.println("get的输出结果:"+method.invoke(object));
- }
-
- }
- public static void main(String[] args) throws Exception {
- Object studentObject = Student.class.getConstructor(String.class,int.class,String.class).newInstance("张三",20,"保定");
- getClassName(studentObject);
- getField(studentObject);
- getMethod(studentObject);
- getAction(studentObject);
-
- }
- }
- reflect.className=com.qcby.reflect.Person
- reflect.MethodName=getAge
- //1、加载配置文件
- //1.1、创建properties对象
- Properties properties = new Properties();
- //1.2、加载配置文件
- ClassLoader classLoader = Person.class.getClassLoader();
- InputStream input = classLoader.getResourceAsStream("com/qcby/reflect/config.properties");
- properties.load(input);
-
- //2、获取配置文件当中定义的数据源
- String className = properties.getProperty("reflect.className");
- String methodName = properties.getProperty("reflect.MethodName");
-
- //反射代码
- Class clz = Class.forName(className);
- Object object = clz.getDeclaredConstructor(String.class,Integer.class,Integer.class).newInstance("gs",23,5);
- Method method = clz.getDeclaredMethod(methodName);
- System.out.println(method.invoke(object));