反射

反射概述

JAVA反射机制是在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为JAVA的反射机制。

实际上,我们创建的每一个类也都是对象,即类本身是java.lang.Class类的实例对象。这个实例对象称之为类对象,也就是Class对象。

Class对象特点

反射 - 图1

从图中可以得出以下几点:

  • Class 类的实例对象表示正在运行的 Java 应用程序中的类和接口。也就是jvm中有很多的实例,每个类都有唯一的Class对象。
  • Class 类没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机自动构造的。也就是说我们不需要创建,JVM已经帮我们创建了。
  • Class 对象用于提供类本身的信息,比如有几种构造方法, 有多少属性,有哪些普通方法

反射的使用

初步使用

先创建一个类

  1. import org.junit.Test;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.Field;
  4. import java.lang.reflect.InvocationTargetException;
  5. import java.lang.reflect.Method;
  6. public class Person {
  7. private String name;
  8. private int age;
  9. public Person() {
  10. }
  11. @Override
  12. public String toString() {
  13. return "Person{" +
  14. "name='" + name + '\'' +
  15. ", age=" + age +
  16. '}';
  17. }
  18. public String getName() {
  19. return name;
  20. }
  21. public void setName(String name) {
  22. this.name = name;
  23. }
  24. public int getAge() {
  25. return age;
  26. }
  27. public void setAge(int age) {
  28. this.age = age;
  29. }
  30. public Person(String name, int age) {
  31. this.name = name;
  32. this.age = age;
  33. }
  34. public void show(){
  35. System.out.println("你好,我是一个人");
  36. }
  37. public void showNation(){
  38. System.out.println("我的国际是");
  39. }
  40. }

通过反射创建对应的运行时类的对象

  1. import org.junit.Test;
  2. import java.util.Random;
  3. /*
  4. 通过反射创建对应的运行时类的对象
  5. */
  6. public class NewInstanceTest {
  7. @Test
  8. public void test1() throws IllegalAccessException, InstantiationException {
  9. Class<Person> clazz = Person.class;
  10. /*
  11. newInstance():调用此方法,创建对应的运行时类的对象,内部调用了运行时类的空参构造器
  12. */
  13. Person obj = clazz.newInstance();
  14. System.out.println(obj);
  15. }
  16. @SuppressWarnings("SwitchStatementWithoutDefaultBranch")
  17. @Test
  18. public void test2(){
  19. int num=new Random().nextInt(3);
  20. String classPath="";
  21. switch (num){
  22. case 0:
  23. classPath="java.util.Date";
  24. break;
  25. case 1:
  26. classPath="java.sql.Date";
  27. break;
  28. case 2:
  29. classPath="Person";
  30. break;
  31. }
  32. try {
  33. Object obj = getInstance(classPath);
  34. System.out.println(obj);
  35. } catch (ClassNotFoundException e) {
  36. e.printStackTrace();
  37. } catch (IllegalAccessException e) {
  38. e.printStackTrace();
  39. } catch (InstantiationException e) {
  40. e.printStackTrace();
  41. }
  42. }
  43. /*
  44. 创建一个指定类的对象。
  45. classpath:指定类的全类名
  46. */
  47. public Object getInstance(String classpath) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
  48. Class<?> clazz = Class.forName(classpath);
  49. return clazz.newInstance();
  50. }
  51. }
  1. import org.junit.Test;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.Field;
  4. import java.lang.reflect.InvocationTargetException;
  5. import java.lang.reflect.Method;
  6. public class ReflectionTest {
  7. //反射之前对于Person的操作
  8. @Test
  9. public void test1(){
  10. //1、创建Person类的对象
  11. Person tom = new Person("Tom", 12);
  12. //通过对象,调用其内部的属性、方法
  13. tom.setAge(10);
  14. System.out.println(tom.toString());
  15. tom.show();
  16. //再Person类外部,不可以通过Person类的对象调用其内部私有结构。
  17. //比如:name,showNation()以及私有的构造器
  18. }
  19. //反射之后对于Person的操作
  20. @Test
  21. public void test2() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
  22. Class clazz= Person.class;
  23. //1、通过反射来创建Person类的对象
  24. Constructor cons=clazz.getConstructor(String.class,int.class);
  25. Object obj=cons.newInstance("Tom",12);
  26. Person p=(Person)obj;
  27. System.out.println(p.toString());
  28. //2、通过反射,调用对象指定的属性、方法
  29. //调用属性
  30. Field age = clazz.getDeclaredField("age");
  31. //反射的那个类中构造方法被private权限修饰符修饰了
  32. //private修饰的成员(变量和方法)语法上只能在本类中进行访问,
  33. // 但是也有例外,如果使用的是反射技术,可以通过setAccessible(true)进行暴力访问。
  34. age.setAccessible(true);
  35. age.set(p,10);
  36. System.out.println(p.toString());
  37. //调用方法
  38. Method shows = clazz.getDeclaredMethod("show");
  39. shows.invoke(p);
  40. }
  41. //获取class的实例的方式
  42. @Test
  43. public void test3() throws ClassNotFoundException {
  44. //方式一、调用运行时类的属性:.class
  45. Class clazz1 = Person.class;
  46. System.out.println(clazz1);
  47. //方式二:通过运行时类的对象,调用getClass()
  48. Person p1 = new Person();
  49. Class clazz2 = p1.getClass();
  50. System.out.println(clazz2);
  51. //方式三:调用class的静态方法:forName(String classPath)
  52. Class clazz3 = Class.forName("Person");
  53. System.out.println(clazz3);
  54. }
  55. }

反射的进一步使用

首先创建一个接口:

  1. package java1;
  2. public interface MyInterface {
  3. void info();
  4. }
  1. 创建一个注解
  2. package java1;
  3. import java.lang.annotation.Retention;
  4. import java.lang.annotation.RetentionPolicy;
  5. import java.lang.annotation.Target;
  6. import static java.lang.annotation.ElementType.*;
  7. @Target({TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
  8. @Retention(RetentionPolicy.RUNTIME)
  9. public @interface MyAnnotation {
  10. String value() default "hello";
  11. }

再创建一个父类:

  1. package java1;
  2. import java.io.Serializable;
  3. public class Creature<T> implements Serializable {
  4. private char gender;
  5. public double weight;
  6. private void breath(){
  7. System.out.println("生物呼吸");
  8. }
  9. private void eat(){
  10. System.out.println("生物吃东西");
  11. }
  12. }

再创建一个Person类实现接口和继承父类:

  1. package java1;
  2. @MyAnnotation(value = "hi")
  3. public class Person extends Creature<String> implements Comparable<String>,MyInterface{
  4. private String name;
  5. int age;
  6. public int id;
  7. public Person(){
  8. }
  9. @MyAnnotation(value = "abc")
  10. private Person(String name){
  11. this.name=name;
  12. }
  13. Person(String name,int age){
  14. this.name=name;
  15. this.age=age;
  16. }
  17. @MyAnnotation(value = "Chinese")
  18. private String show(String nation){
  19. System.out.println("我的国籍是:"+nation);
  20. return nation;
  21. }
  22. public String display(String interest){
  23. return interest;
  24. }
  25. @Override
  26. public void info(){
  27. System.out.println("我是一个人");
  28. }
  29. @Override
  30. public int compareTo(String o) {
  31. return 0;
  32. }
  33. }

首先是获取当前运行时类的属性结构:

  1. package java2;
  2. import java1.Person;
  3. import org.junit.Test;
  4. import java.lang.reflect.AnnotatedType;
  5. import java.lang.reflect.Field;
  6. /*
  7. * 获取当前运行时类的属性结构
  8. * */
  9. public class FiledTest {
  10. @Test
  11. public void test1(){
  12. Class<Person> clazz = Person.class;
  13. //获取属性结构
  14. //getFields():获取当前运行时类及其父类中声明为public访问权限的属性
  15. Field[] fields = clazz.getFields();
  16. for (Field field : fields) {
  17. System.out.println(field);
  18. }
  19. //getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中的属性)
  20. Field[] declaredFields = clazz.getDeclaredFields();
  21. for (Field declaredField : declaredFields) {
  22. System.out.println(declaredField);
  23. }
  24. }
  25. @Test
  26. public void test2(){
  27. Class<Person> clazz = Person.class;
  28. Field[] declaredFields = clazz.getDeclaredFields();
  29. for (Field f : declaredFields) {
  30. //1、权限修饰符
  31. int modifiers = f.getModifiers();
  32. System.out.println(modifiers);
  33. //2、数据类型
  34. AnnotatedType annotatedType = f.getAnnotatedType();
  35. System.out.println(annotatedType);
  36. //3、变量名
  37. String name = f.getName();
  38. System.out.println(name);
  39. }
  40. }
  41. }

获取运行时类的方法结构:

  1. package java2;
  2. import java1.Person;
  3. import org.junit.Test;
  4. import java.lang.annotation.Annotation;
  5. import java.lang.reflect.Method;
  6. import java.lang.reflect.Modifier;
  7. /*
  8. 获取运行时类的方法结构
  9. */
  10. public class MethodTest {
  11. @Test
  12. public void test1(){
  13. Class<Person> clazz = Person.class;
  14. //getMethods():获取当前运行时类及其所有父类中声明为public权限的方法。
  15. Method[] methods = clazz.getMethods();
  16. for (Method method : methods) {
  17. System.out.println(method);
  18. }
  19. System.out.println();
  20. //getDeclaredMethods():获取当前运行时类中声明的所有方法。不包含父类中声明的方法。
  21. Method[] declaredMethods = clazz.getDeclaredMethods();
  22. for (Method declaredMethod : declaredMethods) {
  23. System.out.println(declaredMethod);
  24. }
  25. }
  26. @Test
  27. public void test2(){
  28. Class<Person> clazz = Person.class;
  29. Method[] declaredMethods = clazz.getDeclaredMethods();
  30. for (Method declaredMethod : declaredMethods) {
  31. //1、获取方法声明中的注解
  32. Annotation[] annos = declaredMethod.getAnnotations();
  33. for (Annotation anno : annos) {
  34. System.out.println(anno);
  35. }
  36. //2、权限修饰符
  37. System.out.print(Modifier.toString(declaredMethod.getModifiers())+"\t");
  38. //3、返回值类型
  39. System.out.print(declaredMethod.getReturnType()+"\t");
  40. //4、方法名
  41. System.out.println(declaredMethod.getName()+"\t");
  42. System.out.println();
  43. }
  44. }
  45. }

其他:

  1. package java2;
  2. import java1.Person;
  3. import org.junit.Test;
  4. import java.lang.reflect.Constructor;
  5. public class OtherTest {
  6. /*
  7. 获取构造器结构
  8. */
  9. @Test
  10. public void test1(){
  11. Class<Person> clazz = Person.class;
  12. //getConstructors():当前运行时类中声明为public的构造器
  13. Constructor<?>[] constructors = clazz.getConstructors();
  14. for (Constructor<?> c : constructors) {
  15. System.out.println(c);
  16. }
  17. Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
  18. for (Constructor<?> d : declaredConstructors) {
  19. System.out.println(d);
  20. }
  21. }
  22. /*
  23. 获取运行时类的父类
  24. */
  25. @Test
  26. public void test2(){
  27. Class<Person> clazz = Person.class;
  28. Class<? super Person> superclass = clazz.getSuperclass();
  29. System.out.println(superclass);
  30. }
  31. /*
  32. 获取运行时类的接口
  33. */
  34. @Test
  35. public void test3(){
  36. Class<Person> clazz = Person.class;
  37. Class<?>[] interfaces = clazz.getInterfaces();
  38. for (Class<?> anInterface : interfaces) {
  39. System.out.println(anInterface);
  40. }
  41. }
  42. /*
  43. 获取运行时类的包
  44. */
  45. @Test
  46. public void test4(){
  47. Class<Person> personClass = Person.class;
  48. Package aPackage = personClass.getPackage();
  49. System.out.println(aPackage);
  50. }
  51. }

调用运行时类中指定的结构:属性、方法、构造器:

  1. package java2;
  2. import java1.Person;
  3. import org.junit.Test;
  4. import java.lang.reflect.Field;
  5. import java.lang.reflect.InvocationTargetException;
  6. import java.lang.reflect.Method;
  7. /*
  8. 调用运行时类中指定的结构:属性、方法、构造器
  9. */
  10. public class ReflectionTest {
  11. @Test
  12. public void test1() throws Exception {
  13. Class<Person> clazz = Person.class;
  14. //创建运行时类的对象
  15. Person p = (Person) clazz.newInstance();
  16. //获取指定的属性
  17. Field id = clazz.getField("id");
  18. /*
  19. 设置当前属性的值
  20. set():参数1:指明设置哪个对象的属性 参数2:将此属性值设置为多少
  21. */
  22. id.set(p,1001);
  23. /*
  24. 获取当前属性的值
  25. get():参数1:获取哪个对象的当前属性值
  26. */
  27. int pID= (int) id.get(p);
  28. System.out.println(pID);
  29. }
  30. /*
  31. 如何操作运行时类中的指定的属性
  32. */
  33. @Test
  34. public void test2() throws IllegalAccessException, InstantiationException, NoSuchFieldException {
  35. Class<Person> clazz = Person.class;
  36. Person p = clazz.newInstance();
  37. //getDeclaredField("name"):获取运行时类中指定变量名的属性
  38. Field name = clazz.getDeclaredField("name");
  39. //保证当前属性是可访问的
  40. name.setAccessible(true);
  41. //获取,设置指定对象的属性值
  42. name.set(p,"Tom");
  43. System.out.println(name.get(p));
  44. }
  45. /*
  46. 如何操作运行时类中的指定方法
  47. */
  48. @Test
  49. public void test3() throws Exception {
  50. Class<Person> clazz = Person.class;
  51. //创建运行时类的对象
  52. Person p = clazz.newInstance();
  53. /*
  54. 获取指定的方法
  55. getDeclaredMethod("show", String.class):参数1:指明获取的方法名称 参数2:指明获取的方法的形参列表,可变形参
  56. */
  57. Method show = clazz.getDeclaredMethod("show", String.class);
  58. show.setAccessible(true);
  59. /*
  60. 调用方法的invoke():参数1:方法的调用者 参数2:给方法形参赋值的实参
  61. */
  62. show.invoke(p,"CHN");
  63. }
  64. }