Java反射机制:
参考博客:http://www.cnblogs.com/bojuetech/p/5896551.html
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能调用它的任意一个方法和属性;这种动态获取的信息以及状态调用对象的方法的功能成为Java语言的反射机制
Class:描述类本身的类
Class是一个类,一个描述类的类(即描述类本身),封装了 描述方法的Method,描述字段的Field,描述构造器的Contstructor等属性
对象反射可以得到的信息:某个类的数据成员名、方法和构造器、类实现的接口
对于每个类而言,JRE都为其保留一个不变的Class类型的对象,一个Class对象包含了特定某个类的有关信息
Class对象只能由系统建立对象
一个类在JVM中只会有一个Class实例
反射机制获取类有三种方法:
直接通过类名.class
clazz = Person.class;
通过对象的getClass()方法获取
Object obj = new Person(); clazz = obj.getClass();
通过全类名获取,但可能抛出ClassNotFoundException异常
clazz = Class.forName("com.java.reflection.Person");
clazz使用newInstance创建对象:
使用Class类的newInstance()创建类的一个对象
实际调用的是类的无参构造器(所以写类的时候,要写一个无参的构造器)
Class clazz = Class.forName("com.java.reflection.Person"); Object obj = clazz.newInstance();
ClassLoader加载器:
类加载器是用于将类装入JVM的
JVM有两种类型的类加载器:启动类加载器(bootstrap)和用户自定义加载器(user-defined class loader)
JVM运行时会产生3个类加载器组成的初始化加载器层次结构:
public void testClassLoader1() throws ClassNotFoundException, IOException { //1、获取一个系统的类加载器 ClassLoader classLoader = ClassLoader.getSystemClassLoader(); System.out.println("系统的类加载器-->" + classLoader); //2、获取系统类加载器的父类加载器(扩展类加载器(extensions classLoader)) classLoader = classLoader.getParent(); System.out.println("扩展类加载器-->" + classLoader); //3、获取扩展类加载器的父类加载器 //输出为Null,无法被Java程序直接引用 classLoader = classLoader.getParent(); System.out.println("启动类加载器-->" + classLoader); //4、测试当前类由哪个类加载器进行加载 ,结果就是系统的类加载器 classLoader = Class.forName("com.java.reflection.Person").getClassLoader(); System.out.println("当前类由哪个类加载器进行加载-->"+classLoader); //5、测试JDK提供的Object类由哪个类加载器负责加载的 classLoader = Class.forName("java.lang.Object").getClassLoader(); System.out.println("JDK提供的Object类由哪个类加载器加载-->" + classLoader); }
Method:对应类中的方法
Class clazz = Class.forName("com.java.reflection.Person"); //1、得到clazz 对应的类中有哪些方法,不能获取private方法 Method[] methods = clazz.getMethods(); System.out.print(" getMethods: "); for (Method method : methods){ System.out.print(method.getName() + ", "); } //2、获取所有的方法(且只获取当着类声明的方法,包括private方法) Method[] methods2 = clazz.getDeclaredMethods(); System.out.print(" getDeclaredMethods: "); for (Method method : methods2){ System.out.print(method.getName() + ", "); } //3、获取指定的方法
//第一个参数是方法名,后面的是方法里的参数 Method method = clazz.getDeclaredMethod("setName",String.class); System.out.println(" method : " + method);
//第一个参数是方法名,后面的是方法里的参数 Method method2 = clazz.getDeclaredMethod("setName",String.class ,int.class); System.out.println("method2: " + method2); //4、执行方法! Object obj = clazz.newInstance(); method2.invoke(obj, "draco", 17);
Methos.invoke()方法:调用Method对象表示的底层方法
public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
obj:调用底层方法的对象(调用谁的方法就是用谁的对象)
args:方法调用的参数
Field字段:
Class clazz = Class.forName("com.java.reflection.Person"); //1、获取字段 //1.1 获取Field的数组,私有字段也能获取 Field[] fields = clazz.getDeclaredFields(); for (Field field: fields) { System.out.print(field.getName() + ", "); } //1.2 获取指定名字的Field(如果是私有的,见下面的4) Field field = clazz.getDeclaredField("name"); System.out.println(" 获取指定Field名=: " + field.getName()); Person person = new Person("draco", 17);
//2、获取指定对象的Field的值 Object val = field.get(person); System.out.println("获取指定对象字段'name'的Field的值=: " + val); //3、设置指定对象的Field的值 field.set(person, "harry"); System.out.println("设置指定对象字段'name'的Field的值=: " + person.name); //4、若该字段是私有的,需要调用setAccessible(true)方法 Field field2 = clazz.getDeclaredField("age"); field2.setAccessible(true); System.out.println("获取指定私有字段名=: " + field2.getName());
Constructor:构造器
String className = "com.java.reflection.Person"; Class<Person> clazz = (Class<Person>) Class.forName(className); //1.获取Constructor对象 Constructor<Person>[] constructors = (Constructor<Person>[]) Class.forName(className).getConstructors(); for (Constructor<Person> constructor: constructors) { System.out.println(constructor); } Constructor<Person> constructor = clazz.getConstructor(String.class, Integer.class); System.out.println("指定的-->" + constructor); //2.调用构造器的newInstance()方法创建对象 Object obj= constructor.newInstance("ron", 11);
Annotation:注解
Annotation是代码中的特殊标记,可以在编译、类加载、运行时被读取,并执行相应的处理;通过Annotation,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入补充信息
Annotation可以象修饰符一样被使用,可用于修饰包、类、构造器、方法、参数、成员变量、局部变量的声明,这些信息被保存在Annotation的“name=value”中
Annotation能用于为程序元素(类、方法、成员变量等)设置元数据
基本的Annotatio:
使用时在前面加@
@override:限定重写父类方法
@Deprecated:用于表示某个程序元素(类、方法等)已过时
@SuppressWarnings:抑制编译器警告
自定义的Annotation:
使用@interface关键字
Annotation的成员变量在Annotation定义中以无参数的形式声明,其方法名和返回值定义了该成员的名字和类型
可以在定义Annotation的成员变量时为其指定初始值,指定成员变量的初始值可以使用default关键字
没有成员定义的Annotation称为标记,包含成员变量的Annotation称为元数据Annotation