目录
- java反射机制
- 什么是反射?
- 反射的功能:
- 反射常用类:
- 1.Class枚举类
- 2.Constructor构造器
- 3.Method方法类
- 4.Field变量类
- 反射运行指示图
- 通过反射获取对象
- 总结
java反射机制
什么是反射?
在java开发中有一个非常重要的概念就是java反射机制,也是java的重要特征之一。反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力,通过反射可以调用私有方法和私有属性,大部分框架也都是运用反射原理的。java通常是先有类再有对象,有对象就可以调用方法或者属性,java中的反射其实是通过Class对象来调用类里面的方法。
反射的功能:
①在运行时判断任意一个对象所属的类;
②在运行时构造任意一个类的对象;
③在运行时判断任意一个类所具有的成员变量和方法;
④在运行时调用任意一个对象的方法;
⑤生成动态代理。
Java的反射机制它知道类的基本结构,这种对Java类结构探知的能力,我们称为Java类的“自审”。如eclipse中,一按点,编译工具就会自动的把该对象能够使用的所有的方法和属性全部都列出来,供用户进行选择。这就是利用了Java反射的原理,是对我们创建对象的探知、自审。
反射常用类:
1.Class枚举类
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。
Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。
Person p = new Person();
//获取class对象的方式1
// 需要依赖
Class clazz = p.getClass();
// 方式2 在编译之前就知道要操作的class的名称是什么
Class clacc = Person.class;
Class clazz = Class.forName("com.openlab.test.Person");
Constructor[] con = clazz.getConstructors();
Method[] methods = clazz.getDeclaredMethods();
Field[] fields = clazz.getDeclaredFields();
System.out.println(con.length);
System.out.println(methods.length);
System.out.println(fields.length);
2.Constructor构造器
Constructor 提供关于类的单个构造方法的信息以及对它的访问权限。Constructor 允许在将实参与带有基础构造方法的形参的 newInstance() 匹配时进行扩展转换,但是如果发生收缩转换,则抛出 IllegalArgumentException。
3.Method方法类
Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。
Method 允许在匹配要调用的实参与基础方法的形参时进行扩展转换;但如果要进行收缩转换,则会抛出 IllegalArgumentException。
4.Field变量类
Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。 Array 允许在执行 get 或 set 访问操作期间进行扩展转换,但如果将发生收缩转换,则抛出一个 IllegalArgumentException。
反射运行指示图
通常情况下我们只能在编写源代码时能够清楚的了解到对象的相关属性和方法,常常这些方法是被固定的,程序进入编译之后变不能更改的,但是java加入了反射机制,便可以做到编译之后还能对程序做出更改。
通过反射获取对象
package com.openlab.test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
// Person p = new Person();
// //获取class对象的方式1
// // 需要依赖
// Class clazz = p.getClass();
// // 方式2 在编译之前就知道要操作的class的名称是什么
// Class clacc = Person.class;
//
// Constructor[] con = clazz.getConstructors();
// Method[] methods = clazz.getDeclaredMethods();
// Field[] fields = clazz.getDeclaredFields();
//
// System.out.println(con.length);
// System.out.println(methods.length);
// System.out.println(fields.length);
// 方式3 常用
Class clazz;
try {
clazz = Class.forName("com.openlab.test.Person");
Constructor con = clazz.getDeclaredConstructor(new Class[]{String.class,int.class});
con.setAccessible(true);
Person p = (Person) con.newInstance(new Object[]{"张三疯",99});
System.out.println(p);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Person p = (Person) clazz.newInstance();
}
}
那么为什么要使用这种方式来创建对象呢,原因很简单,使用反射来创建对象,最直接的原因就是因为,在写底层代码的时候,程序员对于要创建的对象有很多的不确定性,而正常的创建对象需要知道类名,而很多使用在使用反射的创建对象时,都是只给了个泛型,所以在不确定类型的情况下创建对象是反射独有的功能。