反射机制
反射可以实现在运行时可以知道任意一个类的属性和方法.
类一旦加载进内存,就会变成Class对象(字节码对象)
元数据:描述输的的描述数据.
反射:得到类的元数据的过程.
在运行时期,动态的去获取某一个类中的成员信息.(构造器/属性/方法/接口/父类等等)
并且把类中的每一种成员都描述成一个新的类
Class: 表示所有的类
Constructor: 表示所有的构造方法
Method: 表示所有的方法
Field: 表示所有的字段
Class类是设计为泛型,所以Class类可以提供任一类的class文件
例如:
Java.util.Date; 使用Class类表示 class Class<Java.util.Date>;
java.lang.Byte; 使用Class类表示 class Class<java.lang.Byte>;
如何获取Class对象
下面举例获取 java.lang.String 的字节码对象
上述是三种获取Class对的方式,基本数据类型不能表示为对象,也就不能使用getClass的方式,基本数据类型没有类名的概念,也不能使用Class.forName的方式,所以:
表示基本数据类型的字节码对象 所有的数据类型都有Class属性
Class 对象名 = 数据类型.class
九大内置Class都使用以上方式创建字节码对象:
byte short int long float double char boolean
数组创建字节码对象的方式
在Object类中说明数组也属于对象,可以调用Object类中的方法.所以创建数组的字节码对象的方式有两种:
1): Class 对象名 = 数组类型[].class;
2): Class 对象名 = 数组名.getClass();
注意:每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
所以:同数据类型,同维数的数组的Class对象是相等的.不区分数组内元素的个数,值.
Class:描述所有的类/类型,所以Class类中应该具有所有类型的相同方法
Object:描述所有的对象,所以在Object类中应该具有所有对象的共同的方法.
通过反射来获取某一个类的构造器:
1):获取该类的字节码对象
常规类获取该类的字节码对象有以上的三种方式
2):获取该类的构造器
①: Constructor<?> [] getConstructors();返回表示的类的所有公共构造方法,存放在Constructor数组中。
②: Constructor<?>[] getDeclaredConstructors();返回该类声明的所有构造方法。 存放在Constructor数组中。
使用获取的构造器创建对象
步骤:
1):线找到构造器所在类的字节码对象
2):获取构造器对象
3):使用反射创建对象
对于无参数外界可以直接访问的构造方法推荐使用该类中的该方法:
public T newInstance(Object... initargs);获取该类的构造器对象
对于有参数,则必须要获取该类有参的构造方法,然后在通过Constructor类中的newInstance加参数创建,私有的则需要设置当前的构造器可以被访问才能创建对象.
使用反射来操作类中的方法
步骤:
1):线找到构造器所在类的字节码对象
2):获取构造器对象
3):使用反射创建对象
4):通过对象操作类中的方法
下列第一二种方法获取的方法列表是无序的
Method[] getMethods(); 获取该类及其父类和接口的所有公共的方法
Method[] getDeclaredMethods(); 获取本类的所有的方法.
Method getDeclaredMethod(形参数据类型.class) ;获取该类指定的方法
获取私有的方法则需要设置当前的方法可以被访问才能创建对象.
import java.lang.reflect.Constructor;
public Student(int a) { private Student(String a) { protected Student(int a, int b) { public class GetConstructor { public static void main(String[] args) throws Exception { //使用反射机制创建非私有构造器对象 } |
使用反射调用方法:
步骤:
1):获取该方法的字节码对象
类名.class得到该类的字节码对象
2):通过字节码对象获取该类的构造方法并创建该类的对象
字节码对象.getDeclaredConstructor(参数.class) 获取该类的构造器
对于私有的构造器则需要设置当前的构造器可以被访问
构造器.setAccessible(true);
构造器.newInstance(实参..,)得到该类的实例
3):通过字节码对象获取该类的方法
1.Method 对象名 = 字节码对象. getDeclaredMethod(形参数据类型.class) ;获取该类指定的方法
对于私有的方法使用
2.对象名.setAccessible(true);设置可访问私有成员
4):使用反射调用方法
对象名.invoke(该类的实例,实参);来调用该方法
有返回值类型则接收,默认返回值类型为Object
针对于静态方法数组作为形参的调用
使用反射调用静态方法
静态方法不属于任何对象,静态方法属于类本身
此时把invoke方法的第一个参数设置为null即可.
使用反射调用数组参数(可变参数):
王道: 调用方法的时候把实际参数统统作为Object数组的元素的即可.
Methad对象.invoke(方法底层所属对象 , new Object[]{ 所有实参 });
针对于读取泛型的方法 默认提升最高级别 Object
把一个数组设置为Object 类型的时候,不能直接操作数组,则只能使用Array类的方法来操作数组.
文件资源路径的加载:
注:加载properties文件只能使用properties类的load方法
使用方式:使用文件的相对路径,相当于classpath的跟路径(字节码输出目录)
此时使用ClassLoader(类加载器) 类加载器默认是从classpath目录去寻找文件的
推荐使用第二种: