java反射机制
程序员文章站
2022-04-30 09:09:04
...
java 反射机制
反射机制概念
- 在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制。反射被视为动态语言的关键。简单来说反射就是java的各种成分映射成对应的java类。
- 通俗点讲,通过反射,该类对我们来说是完全透明的,想要获取任何东西都可以。包括构造方法,属性,方法。
java反射提供的功能
- 在运行时判断任意一个对象所属的类;
- 在运行时构造任意一个类的对象;
- 在运行时判断任意一个类所具有的成员变量和方法;
- 在运行时调用任意一个对象的方法;
- 生成动态代理。
java不是动态语言,但是通过反射机制实现动态机制。
反射的基础Class类
类名 | 用途 |
---|---|
Class类 | 代表类的实体,在运行的java应用程序中表示类和接口 |
Field类 | 代表类的成员变量(类的属性) |
Method类 | 代表类的方法 |
Constructor类 | 代表类的构造方法 |
- 类是Class类的实例对象,所以说Class类是所有类的类
- 想要解剖一个类,必须先获取该类的字节码文件对象,而解剖使用的是Class类中的方法,所以先要获取每一个字节码文件对应的Class类型的对象。
- Class类由于没有公共的构造方法,Class对象是在类加载的时候由Java虚拟机以及通过调用类加载器中的defineClass 方法自动构造的,因此不能显式地声明一个Class对象。
获取Class的三种方法(获取一个类的字节码对象)
-
使用对象获取,使用对象的getClass获取
Person person = new Person(); Class clazz=person.getClass();
-
使用静态属性class
Class clazz =Person.class;
-
使用Class类的静态方法forName(字符串的类名)
-
类要写全名
Class clazz = Class.forName("")
-
反射的用法
-
获取Class
- 使用上文中的三种方法
-
通过Class获取任意一个类的属性
//获取该类指定属性名的public成员变量,包括父类的 Field field = clazzTwo.getField("number"); //获取该类指定名称声明的变量,即不包括父类的 Field deField = clazzTwo.getDeclaredField("name"); //获取该类所有的public声明的成员变量 Field fields[] = clazzTwo.getFields(); //获取该对象的所有成员变量 Field deFields[] = clazzTwo.getDeclaredFields();
-
通过Class获取任意成员方法
//根据方法名以及参数类型获取,只能获取public声明的方法,包括父类的 Method method = clazzTwo.getMethod("setAge",Integer.class); //根据方法名以及参数名称获取该类声明的所有的属性方法,不包括父类的 Method deMethod = clazzTwo.getDeclaredMethod("setAge", Integer.class); //获取该对象声明的所有的public方法,包括父类的 Method methods[] = clazzTwo.getMethods(); //获取该对象声明的所有的方法,但是不包含父类的方法 Method deMethods[] = clazzTwo.getDeclaredMethods();
-
方法调用
public static void main(String[] args)throws Exception { //获取Class第二种方法 Class clazzTwo = Test.class; //根据方法名以及参数类型获取,只能获取public声明的方法,包括父类的 Method method = clazzTwo.getMethod("setAge",int.class); System.out.println(method); //利用Class创建一个对象的实例 Test test = (Test) clazzTwo.newInstance(); //函数调用 Object value = method.invoke(test,20); //null System.out.println(value); }
首先获取一个类的Class,然后通过这个Class获取该类的setAge方法,然后调用这个方法。我们在调用方法前先实例化一个对象(newInstance()),创建一个实例,这种方法需要改实例化的类具有一个无参构造方法。然后通过invoke对方法进行调用,第一个参数是一个实例化的对象,后面就是具体的参数。
-
通过Class获取构造方法
//获取Class第二种方法 Class clazzTwo = Test.class; //获取无参构造方法,public声明的,包括父类,加上参数时就是获取特定的构造方法 Constructor constructor = clazzTwo.getConstructor(); System.out.println(constructor); //获取该类所有的public声明的构造方法 Constructor constructors[] = clazzTwo.getConstructors(); //获取指定参数的构造方法 Constructor deConstructor = clazzTwo.getDeclaredConstructor(String.class,Integer.class); //获取所有的该类的构造方法,不包括父类的 Constructor deConstructors[] =clazzTwo.getDeclaredConstructors(); Test test = (Test) deConstructor.newInstance("冢狐",21); System.out.println(student.getAge());
反射的用途
利用反射创建数组
public static void main(String[] args)throws ClassNotFoundException {
Class<?> cls = Class.forName("java.lang.String");
Object array = Array.newInstance(cls,5);
// 向数组添加内容
Array.set(array,0,"Hello");
Array.set(array,1,"冢");
Array.set(array,2,"狐");
Array.set(array,3,"java");
// 获取数组中指定位置的内容
System.out.println(Array.get(array,2));
}
开发各类通用框架
Spring:
-
XML配置bean
<bean class="com.zhonghu.UserServiceImpl"> </bean>
-
Spring在启动的时候便会利用反射机制去加载对于的类,然后实例化。如果不存在该类则会抛出异常,通常异常中还会出现invoke方法调用的堆栈信息。
-
当Spring基于注解去实例化对象时,同样利用的是反射机制。下面通过一个简单demo示例,演示一下如何通过反射获得注解信息:
static void initUser(User user) throws IllegalAccessException { // 获取User类中所有的属性(getFields无法获得private属性) Field[] fields = User.class.getDeclaredFields(); // 遍历所有属性 for (Field field : fields) { // 如果属性上有此注解,则进行赋值操作 if (field.isAnnotationPresent(InitSex.class)) { InitSex init = field.getAnnotation(InitSex.class); field.setAccessible(true); // 设置属性的性别值 field.set(user, init.sex().toString()); System.out.println("完成属性值的修改,修改值为:" + init.sex().toString()); } } }