Java笔记--反射
本站字数:108k    本文字数:4k    预计阅读时长:18min    访问次数:次
Java笔记–反射
Java反射机制概述
- Reflection (反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。 
- 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。 
- 正常方式和反射方式的对比:  
 
Java反射机质研究及其应用
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时获取泛型信息
- 在运行时调用任意一个对象的成员变量和方法
- 在运行时处理注解
- 生成动态代理
反射相关的主要API
- java.lang.Class: 代表一个类
- java.lang.reflect.Method:代表类的方法
- java.lang.reflect.Field:代表类的成员变量
- java.lang.reflect.Constructor:代表类的构造器
反射初体验
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 
 | @Testpublic void test1() {
 
 Person p1 = new Person("ABC", 21);
 
 
 p1.age = 18;
 System.out.println(p1.toString());
 p1.show();
 
 
 
 }
 
 
 @Test
 public void test2() throws Exception {
 
 
 Class clazz = Person.class;
 
 Constructor cons = clazz.getConstructor(String.class, int.class);
 
 Object obj = cons.newInstance("Tom", 12);
 System.out.println(obj.toString());
 Person p = (Person)obj;
 System.out.println(p.toString());
 
 
 
 Field age = clazz.getDeclaredField("age");
 age.set(p, 10);
 System.out.println(p.toString());
 
 Method show = clazz.getDeclaredMethod("show");
 show.invoke(p);
 
 System.out.println("*********************************");
 
 
 
 Constructor pS = clazz.getDeclaredConstructor(String.class);
 pS.setAccessible(true);
 Object obj1 = pS.newInstance("Toms");
 Person p1 = (Person)obj1;
 System.out.println(p1.toString());
 
 
 Field name = clazz.getDeclaredField("name");
 name.setAccessible(true);
 name.set(p1, "Thompson");
 System.out.println(p1.toString());
 
 
 Method showNation = clazz.getDeclaredMethod("showNation", String.class);
 showNation.setAccessible(true);
 String nation = (String)showNation.invoke(p, "中国");
 System.out.println(nation);
 }
 
 | 
反射机制和封装性辨析
Q1:通过直接new的方式或反射的方式都可以调用公共的结构,开发中用哪个?
A1:直接使用new的方式
Q2:什么时候会用到反射机制?
A2:不确定创建一个什么样的对象时,需要时用反射机制。
Q3:反射机制一面向对象中的封装性是不是矛盾的?如何看待两个技术?
A3:不矛盾。
Class类的理解和获取Class实例
Class类的理解
- 类的加载过程 - 程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾),此过程是编译过程。接着我们使用java.exe对某个字节码文件,进行解释运行。相当于讲某个字节码文件加载到内存中,此过程叫做类的加载。加载到内存中的类,叫做运行时类,就作为Class的一个实例。 
- 换句话说,Class的实例就对应着一个运行时类。 
- 加载到内存中的运行时类,会缓存一段时间。在此时间之内,我们可以通过不同的方式来获取此运行时类。 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 
 | 
 @Test
 public void test3() throws ClassNotFoundException {
 
 Class<Person> clazz1 = Person.class;
 System.out.println(clazz1.toString());
 
 Person p1 = new Person();
 Class<? extends Person> clazz2 = p1.getClass();
 System.out.println(clazz2.toString());
 
 Class<?> clazz3 = Class.forName("xyz.klenkiven.reflection.Person");
 
 System.out.println("clazz1 == clazz2\t" + (clazz1 == clazz2));
 System.out.println("clazz1 == clazz3\t" + (clazz1 == clazz3));
 
 
 ClassLoader classLoader = ReflectionTest.class.getClassLoader();
 Class<?> clazz4 = classLoader.loadClass("xyz.klenkiven.reflection.Person");
 System.out.println(clazz4.toString());
 
 }
 
 | 
那些类型可以有Class对象
- class: - 内部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类 
- interface:接口 
- []:数组 
- enmu:枚举 
- annotation:注解@interface 
- 基本数据类型 
- void 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | @Testpublic void test4() {
 Class<?> c1 = Object.class;
 Class<?> c2 = Comparable.class;
 Class<?> c3 = String[].class;
 Class<?> c4 = int[][].class;
 Class<?> c5 = ElementType.class;
 Class<?> c6 = Override.class;
 Class<?> c7 = int.class;
 Class<?> c8 = void.class;
 Class<?> c9 = Class.class;
 
 int[] a = new int[10];
 int[] b = new int[100];
 Class<?> c10 = a.getClass();
 Class<?> c11 = b.getClass();
 
 System.out.println(c10 == c11);
 }
 
 | 
了解类的加载器
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | @Testpublic void test1() {
 
 ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
 System.out.println(classLoader);
 
 ClassLoader parent = classLoader.getParent();
 System.out.println(parent);
 
 
 ClassLoader parent1 = parent.getParent();
 System.out.println(parent1);
 
 ClassLoader classLoader1 = String.class.getClassLoader();
 System.out.println(classLoader);
 }
 
 | 
使用ClassLoader加载配置文件
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 
 | @Testpublic void test2() throws Exception {
 
 Properties pros = new Properties();
 
 
 
 
 
 
 
 
 ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
 InputStream resourceAsStream = classLoader.getResourceAsStream("jdbc.properties");
 pros.load(resourceAsStream);
 
 
 String user = pros.getProperty("user");
 String password = pros.getProperty("password");
 
 System.out.println("user = " + user + "  password = " + password);
 
 }
 
 | 
创建运行时类的对象
使用 newInstance() 创建要求:
- 使用这个方法一定需要有一个空参构造器
- 使用这个方法一定需要一个合适的访问权限,通常权限为public
在javabean中要求提供一个public的空参构造器,原因:
- 便于通过反射,创建运行时类的对象
- 便于子类继承此运行时类时,默认调用 super()时,保证父类由此构造器
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 
 | @Testpublic void test02() {
 int num = new Random().nextInt(3);
 String classPath = "";
 switch (num) {
 case 0:
 classPath = "java.util.Date";
 break;
 case 1:
 classPath = "java.util.EnumSet";
 break;
 case 2:
 classPath = "xyz.klenkiven.reflection.Person";
 break;
 }
 try {
 Object obj = getInstance(classPath);
 System.out.println(obj.toString());
 } catch (Exception e) {
 e.printStackTrace();
 }
 }
 
 
 
 
 
 public Object getInstance(String classPath) throws Exception {
 Class<?> clazz = Class.forName(classPath);
 return clazz.newInstance();
 }
 
 | 
获取运行时类的完整结构
获取当前运行时类的属性结构
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | @Testpublic void test1() {
 
 Class<Animal> clazz = Animal.class;
 
 
 System.out.println("getDeclaredFields()");
 Field[] fields = clazz.getFields();
 for (Field f : fields) {
 System.out.println(f);
 }
 System.out.println();
 
 System.out.println("getDeclaredFields()");
 Field[] declaredField = clazz.getDeclaredFields();
 for (Field f: declaredField) {
 System.out.println(f);
 }
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | @Testpublic void test2() {
 Class<Animal> clazz = Animal.class;
 Field[] declaredFields = clazz.getDeclaredFields();
 for (Field f: declaredFields) {
 
 
 int modifiers = f.getModifiers();
 System.out.print(Modifier.toString(modifiers) + "\t");
 
 
 Class<?> type = f.getType();
 System.out.print(f + "\t");
 
 
 String name = f.getName();
 System.out.print(name);
 
 System.out.println();
 }
 }
 
 | 
获取运行时类的方法结构
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | @Testpublic void test1() {
 Class<?> clazz = Animal.class;
 
 
 
 Method[] methods = clazz.getMethods();
 for (Method m: methods) {
 System.out.println(m);
 }
 System.out.println();
 
 
 Method[] declaredMethods = clazz.getDeclaredMethods();
 for (Method m: declaredMethods) {
 System.out.println(m);
 }
 }
 
 | 
- @Xxxx 权限修饰符 返回值类型 方法名 (数据类型 参数名,…) throws XxxException
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 
 | @Testpublic void test2() {
 Class<?> clazz = Animal.class;
 Method[] declaredMethods = clazz.getDeclaredMethods();
 for (Method m: declaredMethods) {
 
 Annotation[] annotations = m.getAnnotations();
 for (Annotation a: annotations) {
 System.out.println(a);
 }
 
 
 System.out.print(Modifier.toString(m.getModifiers()) + "\t");
 
 
 System.out.print(m.getReturnType().getName() + "\t");
 
 
 System.out.print(m.getName());
 
 System.out.print("(");
 
 Class<?>[] parameterTypes = m.getParameterTypes();
 if (!(parameterTypes == null || parameterTypes.length == 0)){
 for (int i = 0; i < parameterTypes.length; i++) {
 if (i != 0)
 System.out.println(", ");
 System.out.print(parameterTypes[i].getName() + " args_" + i);
 }
 }
 System.out.print(")\t");
 
 
 Class<?>[] exceptionTypes = m.getExceptionTypes();
 if (!(exceptionTypes == null || exceptionTypes.length == 0)){
 System.out.print("throws\t");
 for (int i = 0; i < exceptionTypes.length; i++) {
 if (i != 0)
 System.out.print(" ,");
 System.out.print(exceptionTypes[i].getName());
 }
 }
 
 System.out.println();
 }
 }
 
 | 
获取运行时类的构造器结构
- 获取运行时类的构造器 | 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | @Testpublic void test1() {
 
 Class<?> clazz = Animal.class;
 
 Constructor<?>[] constructors = clazz.getConstructors();
 for (Constructor c: constructors){
 System.out.println(c);
 }
 
 System.out.println();
 
 
 Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
 for (Constructor c: declaredConstructors) {
 System.out.println(c);
 }
 }
 
 |  
 
- 其他的属性的获取,可以参考方法部分的获取方法 
获取运行时类的带有泛型的父类
| 12
 3
 4
 5
 6
 7
 
 | @Testpublic void test2() {
 Class<?> clazz = Animal.class;
 
 Class<?> superclass = clazz.getSuperclass();
 System.out.println(superclass);
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 
 | @Testpublic void test3() {
 Class<?> clazz = Animal.class;
 
 Type genericSuperclass = clazz.getGenericSuperclass();
 System.out.println(genericSuperclass.getTypeName());
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | @Testpublic void test4() {
 Class<?> clazz = Animal.class;
 
 Type genericSuperclass = clazz.getGenericSuperclass();
 ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
 
 Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
 
 
 System.out.println(((Class)actualTypeArguments[0]).getName());
 }
 
 | 
获取运行时类实现的接口,所在包,注解等等
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | @Testpublic void test5() {
 Class<?> clazz = Animal.class;
 
 Class<?>[] interfaces = clazz.getInterfaces();
 for (Class<?> c: interfaces) {
 System.out.println(c);
 }
 
 System.out.println();
 
 Class<?> superclass = clazz.getSuperclass();
 
 Class<?>[] interfaces1 = superclass.getInterfaces();
 for (Class<?> c: interfaces1) {
 System.out.println(c);
 }
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 
 | @Testpublic void test6() {
 Class<?> clazz = Animal.class;
 
 Package aPackage = clazz.getPackage();
 System.out.println(aPackage);
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | @Testpublic void test7() {
 Class<?> clazz = Animal.class;
 
 Annotation[] annotations = clazz.getAnnotations();
 for (Annotation a: annotations) {
 System.out.println(a);
 }
 }
 
 | 
调用运行时类的完整结构
调用运行时类中指定的属性
- 获取Class类
- 获取指定的属性
- 修改指定的属性
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | @Testpublic void testField() throws Exception {
 Class<?> clazz = Animal.class;
 
 
 Animal a = (Animal)clazz.newInstance();
 
 
 
 
 Field id = clazz.getField("id");
 
 
 id.set(a, 1001);
 
 
 int aid = (int)id.get(a);
 System.out.println(aid);
 }
 
 | 
上面的这种方法已经是过时或者是用处比较小的方法,一般的话使用下面的getDeclaredField()方法
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | @Testpublic void testField1() throws Exception {
 Class<Animal> clazz = Animal.class;
 
 Animal a = clazz.newInstance();
 
 
 
 Field declaredField = clazz.getDeclaredField("name");
 
 
 declaredField.setAccessible(true);
 
 declaredField.set(a, "Dog");
 
 
 String name = (String)declaredField.get(a);
 System.out.println(name);
 
 }
 
 | 
调用运行时类中指定的方法
- 获取指定的方法
- 保证方法一定是可访问的 setAccessable(true)
- 调用方法的 invoke()
- invoke()方法会返回一个- Object的返回值,但是可以强转为原方法对应的返回值类型
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 
 | @Testpublic void testMethod() throws Exception {
 Class<Animal> clazz = Animal.class;
 
 Animal animal = clazz.newInstance();
 
 
 
 
 Method show = clazz.getDeclaredMethod("show", String.class);
 
 show.setAccessible(true);
 
 
 
 
 
 show.invoke(animal, "犬类");
 
 String breed = (String)show.invoke(animal, "犬类");
 System.out.println(breed);
 
 
 Method showDesc = clazz.getDeclaredMethod("showDesc");
 showDesc.setAccessible(true);
 
 Object returnVal1 = showDesc.invoke(animal);
 
 Object returnVal2 = showDesc.invoke(null);
 System.out.println(returnVal1);
 System.out.println(returnVal2);
 }
 
 | 
调用运行时类中的指定构造器
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | @Testpublic void testConstructor() throws Exception {
 Class<Animal> clazz = Animal.class;
 
 
 
 Constructor<Animal> declaredConstructor = clazz.getDeclaredConstructor(String.class);
 
 declaredConstructor.setAccessible(true);
 
 Animal dog = declaredConstructor.newInstance("Dog");
 
 System.out.println(dog);
 }
 
 | 
附录:测试中使用到的类
Person.java
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 
 | public class Person {
 private String name;
 public int age;
 
 
 
 public Person(String name, int age) {
 this.name = name;
 this.age = age;
 }
 private Person(String name) {
 this.name = name;
 }
 public Person() {
 System.out.println("Person()");
 }
 
 
 
 public void show() {
 System.out.println("我是一个人");
 }
 private String showNation(String nation) {
 System.out.println("我是一个" + nation + "人");
 return nation;
 }
 
 
 
 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;
 }
 
 
 @Override
 public String toString() {
 return "Person{" +
 "name='" + name + '\'' +
 ", age=" + age +
 '}';
 }
 }
 
 | 
Animal一系列的类
- Creature.java
- MyAnnotation.java
- MyInterface.java
Animal.java
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 
 | @MyAnnotationpublic class Animal extends Creature<String> implements Comparable<String>, MyInterface{
 
 private String name;
 int age;
 public int id;
 
 
 
 public Animal() {}
 
 @MyAnnotation(value = "abc")
 public Animal(String name) {
 this.name = name;
 }
 
 Animal(String name, int age) {
 this.name = name;
 this.age = age;
 }
 
 
 
 @MyAnnotation
 private String show(String breed) {
 System.out.println("动物品种是" + breed);
 return breed;
 }
 
 public String display(String sample) throws NullPointerException, ClassNotFoundException {
 return sample;
 }
 
 private static void showDesc() {
 System.out.println("我是一只可爱的动物");
 }
 
 
 @Override
 public int compareTo(String o) {
 return 0;
 }
 
 @Override
 public void info() {
 System.out.println("这是一只动物");
 }
 
 @Override
 public String toString() {
 return "Animal{" +
 "name='" + name + '\'' +
 ", age=" + age +
 ", id=" + id +
 '}';
 }
 }
 
 | 
Creature.java
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | import java.io.Serializable;
 public class Creature<T> implements Serializable {
 private char gender;
 public double weight;
 
 private void breath() {
 System.out.println("生物呼吸");
 }
 
 private void eat() {
 System.out.println("生物吃东西");
 }
 }
 
 | 
MyAnnotaion.java
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 import static java.lang.annotation.ElementType.*;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 
 @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
 @Retention(RetentionPolicy.RUNTIME)
 public @interface MyAnnotation {
 String value() default "hello";
 }
 
 | 
MyInterface.java
| 12
 3
 
 | public interface MyInterface {void info();
 }
 
 |