一、认识java Reflection反射机制
Java Reflecation的定义
Reflection(反射)被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性和方法。
Java反射机制提供的功能
1、在运行时判断任意一个对象所属的类;
2、在运行时构造任意一个类的对象;
3、在运行时判断任意一个类所具有的成员变量和方法;
4、在运行时调用任意一个对象的成员变量和方法;
5、生成动态代理。
反射相关的API
java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造方法
二、公用类
因为在这里,我们会用到一些类,所以我先贴出来,等着下面举例的时候可以参考:
1、Person类:
package com.xiaop.reflection; @MyAnnotation(value = "piper") public class Person extends Creature implements Comparable{ public String name; private int age; public int i; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getI() { return i; } public void setI(int i) { this.i = i; } public Person(String name, int age) { super(); this.name = name; this.age = age; } public Person(String name) { super(); this.name = name; } public Person() { super(); } @Override public int compareTo(Object arg0) { // TODO Auto-generated method stub return 0; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } @MyAnnotation(value = "abc123") public void show(){ System.out.println("我是一个人!"); } private Integer display(String nation,Integer i) throws Exception{ System.out.println("我的国籍是:" + nation); return i; } public static void info(){ System.out.println("中国人!"); } class Bird{ } }
2、Person的父类Creature
package com.xiaop.reflection; public class Creature<T> { private double weight; public String colar; public void health(){ System.out.println("呼吸"); } }
3、Person类继承的接口MyInterface
package com.xiaop.reflection; import java.io.Serializable; public interface MyInterface extends Serializable { }
4、Person类用到的注解Annotation
package com.xiaop.reflection; import static java.lang.annotation.ElementType.CONSTRUCTOR; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.LOCAL_VARIABLE; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.TYPE; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String value(); }
三、Class类
1、在Object类中定义了以下的方法,此方法将被所有子类继承:
● public final Class getClass()
以上的方法返回值的类型是一个Class类,此类是Java反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可以通过对象反射求出类的名称。
2、对照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口。对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个类的有关信息。
3、Class本身也是一个类
4、Class 对象只能由系统建立对象
5、一个类在 JVM 中只会有一个Class实例
6、一个Class对象对应的是一个加载到JVM中的一个.class文件
7、每个类的实例都会记得自己是由哪个 Class 实例所生成
8、通过Class可以完整地得到一个类中的完整结构
1.Class常用的方法:
方法名 |
功能说明 |
static Class forName(String name) |
返回指定类名 name 的 Class 对象 |
Object newInstance() |
调用缺省构造函数,返回该Class对象的一个实例 |
getName() |
返回此Class对象所表示的实体(类、接口、数组类、基本类型或void)名称 |
Class getSuperClass() |
返回当前Class对象的父类的Class对象 |
Class [] getInterfaces() |
获取当前Class对象的接口 |
ClassLoader getClassLoader() |
返回该类的类加载器 |
Class getSuperclass() |
返回表示此Class所表示的实体的超类的Class |
Constructor[] getConstructors() |
返回一个包含某些Constructor对象的数组 |
Field[] getDeclaredFields() |
返回Field对象的一个数组 |
Method getMethod(String name,Class … paramTypes) |
返回一个Method对象,此对象的形参类型为paramType |
例如,有了反射之后,我们可以通过反射创建类的对象,并调用类对象的结构
/** * 有了反射,可以通过反射创建一个类的对象,并调用其中的结构 * @throws Exception */ @Test public void test2() throws Exception { Class<Person> clazz = Person.class; //1.创建clazz对应的运行时类Person类的对象 Person p = (Person) clazz.newInstance(); //2.通过反射调用运行时类的指定的属性 //2.1 Field field = clazz.getDeclaredField("name"); field.set(p, "LiuDeHua"); System.out.println(p); //2.2 Field fieldAge =clazz.getDeclaredField("age"); fieldAge.setAccessible(true); fieldAge.set(p, 20); System.out.println(p); //3.通过反射调用运行时类的指定的方法 Method m = clazz.getMethod("show"); Object objVal = m.invoke(p); Method m1 = clazz.getMethod("display", String.class,Integer.class); Object objVal1 = m1.invoke(p, "zhongguo",30); System.out.println(objVal1); }
2.实例化Class类的对象(四种方法)
第一种:若已知具体的类,通过类的class属性获取,该方法最安全可靠,程序性能最高;
例如:Class clazz = String.Class;
第二种,若已知某个类的事例,调用该事例的getClass方法过去Class对象;
例如:Class clazz = "com.xiaop.Person".getClass();
第三种:已知一个类的全类名,且该类在类路径下,可以通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException;
例如:Class clazz = Class.forName("java.lang.String");
第四种:ClassLoader cl = this.getClass().getClassLoader();
Class clazz = cl.loadClass("类的全类名");
代码示例:
/** * 如何获取Class的实例(3种) * @throws ClassNotFoundException * @throws IllegalAccessException * @throws InstantiationException */ @Test public void test4() throws Exception{ //1.调用运行时类本身的.class属性 Class clazz1 = Person.class; System.out.println(clazz1.getName()); Class clazz2 = String.class; System.out.println(clazz2.getName()); //2.通过运行时类的对象获取 Person p = new Person(); Class clazz3 = p.getClass(); System.out.println(clazz3.getName()); //3.通过Class的静态方法获取.通过此方式,体会一下,反射的动态性。 String className = "com.xiaop.reflection.Person"; Class clazz4 = Class.forName(className); //clazz4.newInstance(); System.out.println(clazz4.getName()); //4.(了解)通过类的加载器 ClassLoader classLoder = this.getClass().getClassLoader(); Class clazz5 = classLoder.loadClass(className); System.out.println(clazz5.getName()); System.out.println(clazz1 == clazz3);//true System.out.println(clazz1 == clazz4);//true System.out.println(clazz1 == clazz5);//true }