目录
反射
(1)Java反射机制
Java反射机制允许程序在执行过程中借助于Reflection API取得任何类的全部内部信息,并直接操作任意对象的内部属性及方法;
在程序中,加载完类以后,堆内存中的方法区就产生了一个Class类型的对象(一个类对应一个Class对象),这个对象就包含了完整的类的结构信息;
反射具有动态性;
反射的主要API
- java.lang.Class
- java.lang.reflect.Method
- java.lang.reflect.Field
- java.lang.reflect.Constructor
(2)反射的功能
1.运行时判断任意一个对象所属的类;
2.运行时判断任意一个类所具有的属性和方法;(包括私有)
3.运行时构造任意一个类的对象;
4.运行时获取泛型信息;
5.运行时调用任意一个对象的属性和方法;
6.运行时处理解析;
7.生成动态代理;
new和反射都可以调用公共的资源,在运行时需要创建不确定对象时用到反射;(动态性)
(3)Class类
类的加载过程
程序经过javac.exe编译后会生成一个或多个字节码文件(xxx.class),java.exe对某个字节码文件进行解释运行,相当于将某个字节码加载到内存中,此过程为类的加载;
加载到内存中的类称为运行时类,此时运行时类是Class类的一个实例;(Class类的对象是一个运行时类)
Class实例
获得Class实例的四种方法
方式一:调用运行时类的属性class
Class personClass = Person.class;//在编译时就确定
方式二:通过运行时类的对象获取
Person person=new Person();
Class personClass = person.getClass();
方式三:通过调用Class类的静态方法:forName(String classPath)
Class personClass=Class.forName("org.hac.java.Person");//在运行时确定
方式四:使用类的加载器
ClassLoader classLoader=ReflectDemo.class.getClassLoader();
Class personClass=classLoader.loadClass("org.hac.java.Person");
类加载器
类加载器的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class的对象,作为方法去中类数据的访问入口;
类缓存:一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间,JVM垃圾回收机制可以回收这些Class对象;
ClassLoader分为引导类加载器、扩展类加载器、系统类加载器
使用ClassLoader加载配置文件
Properties加载配置文件步骤
1.先创建Properties类对象;
2.创建FileInputStream对象;
3.Properties对象调用load(FileInputStream fileInputStream)来加载文件;
4.Properties对象调用getProperty()方法读取;
ClassLoader加载配置文件步骤
ClassLoader classLoader=ReflectDemo.class.getClassLoader();//1.获得ClassLoader对象
Properties properties=new Properties();//2.获得Properties对象
InputStream inputStream=classLoader.getResourceAsStream("...");//3.通过类加载器获得输入流
properties.load(inputStream);//4.加载文件
创建运行时类对象
可以通过反射来创建运行时类的对象;
Class<Student> studentClass=Student.class;//定义泛型后newInstance()返回类型为泛型的类型,如果不定义泛型则默认返回Object类型对象;
Student student = studentClass.newInstance();
//newInstance();创建运行时类的对象,内部调用运行时类空参构造器,使用这个方法需要在类内内部提供空参构造器和设置合适的访问权限;
//使用空参构造器原因:
1.便于通过反射创建运行时类对象;
2.便于子类继承此运行时类时,默认调用super()时,保证父类有此构造器;
反射获得属性结构
Class studentClass=Student.class;
//getFields()
Field[] fields = studentClass.getFields();//获得当前运行时类及其父类中声明为public的属性对象(返回属性数组)
//getField()
Field id=studentClass.getField("id");//获得单个属性对象;
//getDeclaredFileds()
Field[] fields=studentClass.getDeclaredFields();//获得当前运行时类中声明的所有属性(包括父类,无论任何访问权限)
//getDeclaredFiled()
Field id=studentClass.getDeclaredField("id");//获得单个属性对象
//属性对象常用方法
getModifiers()//获得属性权限修饰符,返回整数
1:public
2:private
3:缺省
//如果需要显示原修饰符,调用toString方法
name.toString()
getType()//获得属性的数据类型
getName()//获得属性变量名
反射获得方法结构
getMethods()//返回当前运行时类及其父类中所有声明为public的方法的方法类型数组
getMethod()//返回单个方法对象
getDeclaredMethods()//返回当前运行时类中声明的所有方法,包括父类,无论任何权限
//获得运行时类方法的内部结构
反射获得构造器
getConstructors();//返回当前运行时类中声明为public构造器,返回类型是构造器类型数组
getDeclaredConstructors()//返回当前运行时类的所有构造器
反射获得泛型
getSuperclass()//获得当前运行时类的父类对象
getGenericSuperclass()//获得父类的泛型,返回类型是Type类
反射获得其他结构
//获得接口
getInterfaces()//返回接口数组
//获得运行时类所在包
getPackage()
//获得注解
getAnnotations()//返回注解数组
(4)调用指定结构
调用属性
//1.获得运行时类
Class<Student> studentClass=Student.class;
//2.创建运行时类对象
Student student = studentClass.newInstance();
//3.获得运行时类的指定属性对象
Field name = studentClass.getDeclaredField("name");//一般不用getField()方法
//4.使非public的属性能够修改,否则报异常
name.setAccessible(true);
//5.通过set()方法设置对象的属性值
name.set(student,"hac");
//6.属性对象通过调用get()方法获得对象中的属性值
System.out.println(name.get(student));
//set(Object obj, Object value)
//get(Object obj)
//setAccessible(boolean flag)
调用方法
Class<Student> studentClass=Student.class;
Student student = studentClass.newInstance();
Method say = studentClass.getDeclaredMethod("say");
say.setAccessible(true);
say.invoke(student);//指定对象调用此方法
invoke(Object obj, Object... args)//invoke方法中也可以传入对象参数
调用构造器
Class<Student> studentClass=Student.class;
Constructor<Student> constructor = studentClass.getDeclaredConstructor();
Student student = constructor.newInstance();
getDeclaredConstructor()//获得无参构造器对象,也可以在方法中传入形参获得带参构造器
newInstance()//创建对象
(5)反射的应用
- 动态代理
- Spring、Mybatis框架
- JDBC数据库数据库连接