1、反射的一些基础知识:
- 反射的基本概念:反射的概念是由Smith在1982年首次提出,主要是指程序可以访问、检测和修改它本身状态和行为的一种能力,并根据自身行为的状态和结果,调整或者修改应用所描述行为的状态和相关的语义。Java中,反射是一种强大的工具,是能够创建灵活的代码,这些代码可以在运行时装配,无需在组建之间进行源代码链接。反射允许我们在编写与执行时,是我们的程序代码能够接入装载到JVM中的内部信息,而不是源代码中选定的类协作的代码。这使反射成为构建灵活的主要工具。但是需要注意的是,如果使用不当,反射的成本很高。
- 反射机制的优点:1、反编译:.class --> .java;2、通过反射机制访问java对象的属性,方法,构造方法等。
- 反射的两个缺点:
1、性能问题。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。用于字段和方法接入时反射要远远慢于直接代码。性能问题的程度取决于程序中是如何使用反射的。如果它作为程序运行中相对很少涉及的部分,缓慢的性能将不会是一个问题。
2、使用反射会模糊程序内部实际要发生的事情。程序人员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术会带来维护问题。反射代码比相对应的直接代码更复杂。解决这些问题的最佳方案就是保守地使用反射--仅在于它可以真正增加灵活性的地方--记录其在目标类中的使用。
- 反射机制中主要需要掌握的类型:java.lang.Class;(可以认为代表.class文件) java.lang.reflect.Constructor; java.lang.reflect.Field; java.lang.reflect.Method; java.lang.reflect.Modifier;
- 获取Class类型对象的三种方式:
第一种方式:java.lang.Class类中的静态方法forName(String className)方法返回Class类型的对象,该对象代表的是整个类。(有时候必须使用类全名的字符串作为参数。)(forName静态方法是将某个.class文件装载到JVM中的过程,所以如果类中有静态语句块,静态语句块会执行。)
第二种方式:java中的每个类型都有class属性,如Class c = Employee.class;(不会执行Employee类中的静态语句块。)(需要注意,Class c = int.class; 即c代表int类型。)
第三种方式:java语言中任何一个java对象都有getClass方法,如Employee e = new Employee(); Class c = e.getClass();(java.lang.Object类中的getClass()方法,返回的是这个对象的运行时类。)
- 需要注意的是,在JVM中运行时类存在唯一,即 Class c1 = java.util.Date.class; Class c2 = Class.forName("java.util.Date"); System.out.println(c1 = c2); ,结果为true。
2、通过java.lang.Class类中的newInstance()方法创建由该类对象表示的类的新实例:(底层调用指定类中的无参数构造方法)(Class类可以使用泛型)
3、关于java中的可变长参数:(需要注意,可变长参数可以等同看作数组)
- 可变长参数可以使用length属性:(也可以使用下标,如args[i])
- 需要注意的是,可变长参数只能放在参数列表的最后,以下代码编译不能通过:
4、IO和Properties类的联合应用:
- 从字节输入流中加载适当的list(键值对形式):
- 在指定目录下创建dbinfo.properties文件,文件内容如下:(属性文件中的格式固定,“=”号可以替换成“:”或者是空格。java中规范要求属性文件以“.properties”。如果“空格”,“等号”,“冒号”都有,按最前的作为分隔符。)
- 示例代码:
5、java.lang.Class(类)、java.lang.reflect.Field(类中的属性)和java.lang.reflect.Modifier类(类中的修饰符)
- java.lang.Class类中的getFields[]方法:用于获取Class类对象表示的public修饰符修饰的Field对象数组
- java.lang.Class类中的getDeclaredFields[]方法:用于获取Class类对象表示的所有Field对象数组:
- java.lang.Class类中的getDeclaredField方法:用于获取Class类对象表示的Field对象(通过传递属性名字符串参数)
- java.lang.reflect.Field类中的getType()方法:用于获取Field类对象表示的用于标识声明域的类型的Class对象
- java.lang.Class类中的getName()方法:用于获取Class类对象表示的实体的名字,作为字符串返回(包括类、接口、数组类、基本数据类型或者是void)
- java.lang.Class类中的getSimpleName()方法:用于获取Class类对象表示的在源码中给定的底层类简写的名字
- java.lang.Class类中的getModifiers()方法:用于获取类或者接口中的java语言中的修饰符(编码成int类型)
- java.lang.reflect.Field类中的getModifiers()方法:用于获取Field对象表示的域的java语言修饰符(作为int类型数据返回)
- java.lang.reflect.Modifier类中的toString(int mod)方法:返回指定的修饰符标识的字符串名(通过传入iint类型的参数)
- java.lang.reflect.Field类中的set(Object object, Object value)方法:通过Field类对象相关的field域设置指定的值(指定的值为第二个参数Object value)(第一个参数传递的是包含该属性的类对象)
- java.lang.reflect.Field类中的get(Object obj)方法:(通过在指定的类对象上,返回这个Field对象的域的值)
- java.lang.reflect.AccessibleObject类中的setAccessible(boolean flag)方法:打破封装,将这个对象的可访问标志设置为指定的布尔值(java.lang.reflect.Field继承自java.lang.reflect.AccessibleObject)
6、java.lang.reflect.Method:类中的方法
- java.lang.Class类中的getDeclaredMethods()方法:用于获取Class类对象表示的所有方法对象数组,该数组反射对象类或者接口声明中的所有方法
- java.lang.reflect.Method类中的getReturnType()(获取返回值的Class类型)、getModifers()(获取修饰符表示的int类型的值)、getName()(获取方法的字符串名字)、getParameterTypes()方法(获取形式参数列表表示的Class类型数组):(以下方法和java.lang.reflect.Field类中的方法类似,不赘述)
7、获取某个特定的方法,通过反射机制执行:
- java.lang.Class类中的getDeclaredMethod(String name, Class ... parameterType)方法:用于获取Class类对象相关的Method类对象(通过传递字符串方法名和可变长Class类型的形参列表两个参数)
- java.lang.reflect.Method类中的invoke(Object obj, Object ... args)方法:在传递的指定的对象(第一个参数)调用对象类上的方法,实参列表为传递的指定可变长参数
8、java.lang.reflect.Constructor:类的构造方法
- java.lang.Class类中的getDeclaredConstructor(Class ... parameterTypes)方法:用于获取Class类对象表示的构造器对象,这个构造器对象反射指定类或者接口的构造器
- java.lang.Class类中的getDeclaredConstructors()方法:用于获取Class类对象表示的构造器对象数组,这个构造器对象数组反射在类中声明的所有构造器
- java.lang.reflect.Constructor类中的getModifiers()方法:用于返回Constructor类对象表示构造器的java语言修饰符(作为int类型数据返回)
- java.lang.reflect.Constructor类中的getParameterTypes():用于获取Constructor类对象表示的Class类对象数组,这个类对象数组用于表示在构造器中按照一定次序形式参数类型
- java.lang.reflect.Constructor类中的getGenericExceptionTypes()方法:用于返回Constructor类对象的Type类对象数组,这个数组表示声明抛出的异常
9、获取某个特定的构造方法,然后创建对象:
- java.lang.reflect.Constructor类中的newInstance(Object ... initargs)方法:使用Constructor类对象表示的构造器,创建和初始化构造器声明的类的实例(使用指定的参数列表)
- 示例代码:
10、关于类获取父类和父接口:
- java.lang.Class类中的getSuperclass()方法:用于获取Class类对象表示的实体(类、接口、基本数据类型或者是void)的Class父类对象
- java.lang.Class类中的getInterfaces()方法:通过Class类对象表示的这个类或者接口确定它实现的接口,并返回这个Class类对象