服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - Java的枚举,注解和反射(二)

Java的枚举,注解和反射(二)

2021-09-26 10:59保护眼睛 Java教程

今天小编就为大家分享一篇关于Java枚举,注解与反射原理说明,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

反射

 

什么是反射?

反射是指在程序运行期间,可以通过Reflection Api提供方法可以获取任何类的内部的信息,并能直接操作任意类的方法和属性。反射被视为动态语言的关键。

  1. //在反射之前可以做的事情
  2. @Test
  3. public void Test1() {
  4. //创建Person类的对象
  5. Person person = new Person("name", 78);
  6. //通过对象调用其内部的方法和属性
  7. person.setAge(20);
  8. System.out.println(person.toString());
  9. person.show();
  10. //在Person类的外部,不能通过对象调用其内部的私有的结构
  11. }
  12. //在反射之后可以做的事情
  13. @Test
  14. public void Test2() throws Exception {
  15. //通过反射创建Person类的对象
  16. Class classPerson = Person.class;
  17. Constructor constructor = classPerson.getConstructor(String.class, int.class);
  18. Object object = constructor.newInstance("Tom", 13);
  19. Person person = (Person) object;
  20. System.out.println(person.toString());
  21. //通过反射获取Person内部的属性和方法
  22. Field name = classPerson.getField("name");
  23. name.set(person, "Jack");
  24. System.out.println(person.toString());
  25. //调方法
  26. Method show = classPerson.getDeclaredMethod("show");
  27. show.invoke(person);
  28. //调用私有的构造方法
  29. Constructor constructor1 = classPerson.getDeclaredConstructor(String.class);
  30. constructor1.setAccessible(true);
  31. Person person1 = (Person) constructor1.newInstance("Marry");
  32. System.out.println(person1);
  33. //调用私有的方法
  34. Method showNation = classPerson.getDeclaredMethod("showNation", String.class);
  35. showNation.setAccessible(true);
  36. showNation.invoke(person1, "中国");
  37. }

结果:

未使用反射

Java的枚举,注解和反射(二)

使用反射:

Java的枚举,注解和反射(二)

Person类

  1. package reflection;
  2. /**
  3. * user:ypc;
  4. * date:2021-06-20;
  5. * time: 13:55;
  6. */
  7. public class Person {
  8. public String name;
  9. private int age;
  10. public String getName() {
  11. return name;
  12. }
  13. public void setName(String name) {
  14. this.name = name;
  15. }
  16. public Person() {
  17. }
  18. public int getAge() {
  19. return age;
  20. }
  21. public void setAge(int age) {
  22. this.age = age;
  23. }
  24. public Person(String name, int age) {
  25. this.age = age;
  26. this.name = name;
  27. }
  28. private Person(String name) {
  29. this.name = name;
  30. }
  31. @Override
  32. public String toString() {
  33. return "Person{" +
  34. "name='" + name + '\'' +
  35. ", age=" + age +
  36. '}';
  37. }
  38. public void show() {
  39. System.out.println("I am a person");
  40. }
  41. private String showNation(String nation) {
  42. return nation;
  43. }
  44.  
  45. }

反射的用途

1、在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法 。

2、反射最重要的用途就是开发各种通用框架,比如在spring中,我们将所有的类Bean交给spring容器管理,无论是XML配置Bean还是注解配置,当我们从容器中获取Bean来依赖注入时,容器会读取配置,而配置中给的就是类的信息,spring根据这些信息,需要创建那些Bean,spring就动态的创建这些类。

Java程序中许多对象在运行时会出现两种类型:运行时类型(RTTI)和编译时类型,例如Person p = new Student();这句代码中p在编译时类型为Person,运行时类型为Student。程序需要在运行时发现对象和类的真实信息。而通过使用反射程序就能判断出该对象和类属于哪些类。

在类被加载完成之后,就会在堆区,产生一个Class对象,这个对象就包含了存这个类的全部的结构信息。我们就可以通过这个对象看到这个类的全部的信息。

这个对象就像一面镜子,通过这个镜子可以看到这个类的全部的信息结构。所以称之为反射。

正常的方式:通过引入需要导入的包类的名称---->通过new来实例化---->得到实例化的对象

反射的方式:实例化对象---->通过getClass()方法---->得到完整的包类的名称

反射的具体作用

  • 在运行的时候判断任意的一个对象所属的类
  • 在运行的时候构造任意一个类的对象
  • 在运行 的时候判断任意一个类的成员变量和方法
  • 在运行的时获取泛型的信息
  • 在运行的时候调用任意一个类的成员变量和方法
  • 在运行的时候处理注解
  • 生成动态代理

反射的主要API

类名 用途

Class类 代表类的实体,在运行的Java应用程序中表示类和接口

Field类 代表类的成员变量/类的属性

Method类 代表类的方法

Constructor类 代表类的构造方法

通过直接new 的方式和反射 都可以直接调用公共的结构,在开发的时候应该使用哪一个呢?

建议:使用new 的方式来创建对象。

什么时候使用反射呢?

反射的特性:动态性。就是在编译的时候不知道要创建什么样的对象的时候,可以使用反射方式来创建对象。比如在后端部署的服务器,前端传来的时登录的请求的话,就创建登录对应的对象。前端传来的是注册所对应的请求的话,就创建登录所对应的对象,这就是反射的动态特性。

反射的机制和封装是不矛盾的呢?

封装是告诉你不要调,反射可以调。

Class类

在Object类中定义了以下的方法,此方法将被所有子类继承:

  1. public final Class getClass()

以上的方法返回值的类型是一个Class类,此类是Java反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即可以通过对象反射求出类的名称。

对象使用反射后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口。对于每个类而言,JRE都为其保留一个不变的Class类型的对象。一个Class对象包含了特定某个结构( class/interface/enum/annotation/primitive type/void/[])的有关信息。也就是这些类型可以有Class对象:class 成员内部类、 静态内部类、 局部内部类 、 匿名内部类、接口、数组、枚举、注解、基本的数据类型、void等。

注意:

Class本身也是一个类

Class对象只能由系统建立对象

一个加载的类在JVM中只会有一个Class实例

一个Class对象对应的是一个加载到JVM中的一个.class文件

每个类的实例都会记得自己是由哪个Class实例所生成

通过Class可以完整地得到一个类中的所有被加载的结构

Class类是Reflection的根源,针对任何你想动态加载、运行的类,只有先获得相应的Class对象,才能继续下去。

关于java.lang.Class的理解:

类的加载过程:

程序通过javac.exe命令,生成一个或多个字节码文件。接着使用java.exe命令来对某个字节码文件来解释运行。将字节码文件加载到内存中,这个过程称为类的加载。加载到内存中的类,就被称为运行时类,此运行使类就称为Class 的一个实例。

Class 实例就对应着一个运行时类,加载到内存中的运行时类,会缓存一段时间。在此时间之内,可以通过不同的方式来获取运行时类。

获取Class实例的四种方式

  1. // Class 实例就对应着运行时类
  2. @Test
  3. public void test3() throws ClassNotFoundException {
  4. //方式1 调用运行时类的属性:.class
  5. Class clazz1 = Person.class;
  6. System.out.println(clazz1);
  7. //方式2 通过运行时类的对象来调用
  8. Person person = new Person();
  9. Class clazz2 = person.getClass();
  10. System.out.println(clazz2);
  11.  
  12. //方式3 通过Class的静态方法 forName(类的全路径名称)
  13. Class clazz3 = Class.forName("reflection.Person");
  14. System.out.println(clazz3);
  15. //方式4 通过类加载器:ClassLoader
  16. ClassLoader classLoader = ReflectionDemo1.class.getClassLoader();
  17. Class clazz4 = classLoader.loadClass("reflection.Person");
  18. System.out.println(clazz4);
  19. System.out.println(clazz1 == clazz2);
  20. System.out.println(clazz1 == clazz3);
  21. System.out.println(clazz1 == clazz4);
  22. }

Java的枚举,注解和反射(二)

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

  1. package reflection;
  2. import org.junit.Test;
  3. import java.util.Random;
  4. /**
  5. * user:ypc;
  6. * date:2021-06-21;
  7. * time: 20:36;
  8. */
  9. public class NewInstanceDemo {
  10. @Test
  11. public void test1() throws IllegalAccessException, InstantiationException {
  12. Class<Person> personClass = Person.class;
  13. /*
  14. newInstance()方法可以创建运行时类的实列,其内部也时调用内的无参的构造方法来创建对象
  15. */
  16. Person person = personClass.newInstance();
  17. System.out.println(person);
  18. }
  19. @Test
  20. public void test2() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
  21. //在编译的时候不知道要创建的对象。只有运行的时候才知道要创建的对象
  22. for (int i = 0; i < 100; i++) {
  23. int num = new Random().nextInt(3);
  24. String classPath = "";
  25. switch (num) {
  26. case 0:
  27. classPath = "java.util.Date";
  28. break;
  29. case 1:
  30. classPath = "java.lang.Object";
  31. break;
  32. case 2:
  33. classPath = "reflection.Person";
  34. break;
  35. }
  36. Object object = getInstance(classPath);
  37. System.out.println(object);
  38. }
  39. }
  40. //创建一个指定类的对象
  41. public Object getInstance(String classPath) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
  42. Class clazz = Class.forName(classPath);
  43. return clazz.newInstance();
  44. }
  45. }

通过反射获取运行类的属性及权限修饰符、变量名 、数据的类型

  1. @Test
  2. public void test1(){
  3. //getFields()获取的是运行时类及其父类中public的属性
  4. Class clazz = Person.class;
  5. Field[] fields = clazz.getFields();
  6. for (Field field: fields) {
  7. System.out.println(field);
  8. }
  9. System.out.println();
  10. //getDeclaredFields():获取当前运行类的所有属性
  11. Field[] declaredFields = clazz.getDeclaredFields();
  12. for (Field field:declaredFields) {
  13. System.out.println(field);
  14. }
  15. }

Java的枚举,注解和反射(二)

  1. //权限修饰符 变量名 数据的类型
  2. @Test
  3. public void test2(){
  4. Class clazz = Person.class;
  5. Field[] declaredFields = clazz.getDeclaredFields();
  6. for (Field field:declaredFields) {
  7. //权限修饰符
  8. System.out.println(Modifier.toString(field.getModifiers())+"\t");
  9.  
  10. //变量名
  11. System.out.println(field.getType()+"\t");
  12. //数据的类型
  13. System.out.println(field.getName()+"\t");
  14. }
  15. }

Java的枚举,注解和反射(二)

通过反射获取运行时类的方法结构及其内部结构

  1. package reflection2;
  2. import org.junit.Test;
  3. import java.lang.annotation.Annotation;
  4. import java.lang.reflect.Method;
  5. import java.lang.reflect.Modifier;
  6. /**
  7. * user:ypc;
  8. * date:2021-06-22;
  9. * time: 13:32;
  10. */
  11. public class MethodDemo {
  12. @Test
  13. public void test1() {
  14. //获取当前运行时类及其父类中所有声明为public的方法
  15. Class clazz = Person.class;
  16. Method[] methods = clazz.getMethods();
  17. for (Method method : methods) {
  18. System.out.println(method);
  19. }
  20. System.out.println();
  21. //获取当前运行时类所有的方法
  22. Method[] declaredMethods = clazz.getDeclaredMethods();
  23. for (Method method : declaredMethods) {
  24. System.out.println(method);
  25. }
  26. }
  27. //@xxx注解
  28. //权限修饰符 方法结构 返回值的类型
  29. @Test
  30. public void test2() {
  31. Class clazz = Person.class;
  32. Method[] declaredMethods = clazz.getDeclaredMethods();
  33. for (Method method : declaredMethods) {
  34. //获取方法的注解
  35. Annotation[] annotations = method.getDeclaredAnnotations();
  36. for (Annotation annotation : annotations) {
  37. System.out.print(annotation);
  38. }
  39. //获取权限的修饰符
  40. System.out.print(Modifier.toString(method.getModifiers()) + "\t");
  41. //获取返回值的类型
  42. System.out.print(method.getReturnType().getName() + "\t");
  43. //方法名
  44. System.out.print(method.getName());
  45. System.out.print("(");
  46. //获取形参的列表
  47. Class[] parameterTypes = method.getParameterTypes();
  48. if (!(parameterTypes == null && parameterTypes.length == 0)) {
  49. for (int i = 0; i < parameterTypes.length; i++) {
  50. if (i == parameterTypes.length - 1) {
  51. System.out.print(parameterTypes[i].getName() + " args__" + i);
  52. } else {
  53. System.out.print(parameterTypes[i].getName() + " args__" + i + ",");
  54. }
  55. }
  56. }
  57. System.out.print(")");
  58. //获取方法的异常
  59. Class[] exceptionTypes = method.getExceptionTypes();
  60. if (exceptionTypes.length != 0) {
  61. System.out.print("throws");
  62. for (int i = 0; i < exceptionTypes.length; i++) {
  63. if (i == exceptionTypes.length - 1) {
  64. System.out.print(exceptionTypes[i].getName());
  65. } else {
  66. System.out.print(exceptionTypes[i].getName() + ",");
  67. }
  68. }
  69. }
  70. System.out.println();
  71. }
  72. }
  73. }

test1():

Java的枚举,注解和反射(二)

test2():

Java的枚举,注解和反射(二)

通过反射获取运行时类的构造结构

  1. @Test
  2. public void test1() {
  3. Class clazz = Person.class;
  4. //获取运行时类的public构造方法
  5. Constructor[] constructors = clazz.getConstructors();
  6. for (Constructor constructor : constructors) {
  7. System.out.println(constructor);
  8. }
  9. System.out.println();
  10. //获取当前运行时类中的所有的构造方法
  11. Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
  12. for (Constructor declaredConstructor : declaredConstructors) {
  13. System.out.println(declaredConstructor);
  14. }
  15. }

Java的枚举,注解和反射(二)

通过反射获取运行时类的父类和父类的泛型、注解、接口、所在包

反射所使用到的包、接口、类、注释等

延伸 · 阅读

精彩推荐