2025年Java反射机制

Java反射机制Java 反射机制 一 反射的概念 Java 反射是基于正射而言的 所谓正射就是通过 new 的形式创建对象 也就是我们常说的 new 方法 我们知道 代码编译后 java 的文件被编译成 class 的二进制文件 在运行过程中只有用到了这个类 JVM 类加载器才会将 class 文件加载到内存中

大家好,我是讯享网,很高兴认识大家。

Java反射机制

一、反射的概念

  Java反射是基于正射而言的,所谓正射就是通过new的形式创建对象,也就是我们常说的new()方法。我们知道,代码编译后.java的文件被编译成.class的二进制文件,在运行过程中只有用到了这个类JVM类加载器才会将.class文件加载到内存中。

  Java反射是指Java在运行时具有自观察的能力,能对于任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象都能调用它的方法和属性;这种动态获取信息以及动态调用该对象的方法的功能称为Java的反射机制。

二、为什么需要Java反射机制

  以Java的工厂模式举例:

  产品接口类

public interface Shape { void produce(); } 

讯享网

  产品实现类

讯享网public class Square implements Shape { @Override public void produce() { System.out.println("produce Square!"); } } public class Rectangle implements Shape { @Override public void produce() { System.out.println("produce Rectangle!"); } } public class Circle implements Shape { @Override public void produce() { System.out.println("produce Circle!"); } } 

  工厂类

public class ShapeFactory { //使用 getShape 方法获取形状类型的对象 public Shape getShape(String shapeType){ if(shapeType == null){ return null; } if(shapeType.equalsIgnoreCase("CIRCLE")){ return new Circle(); } else if(shapeType.equalsIgnoreCase("RECTANGLE")){ return new Rectangle(); } else if(shapeType.equalsIgnoreCase("SQUARE")){ return new Square(); } return null; } } 

  测试类

讯享网@SpringBootTest public class FactoryTest { @Test public void test1(){ ShapeFactory shapeFactory = new ShapeFactory(); //获取 Circle 的对象,并调用它的 draw 方法 Shape shape1 = shapeFactory.getShape1("CIRCLE"); //调用 Circle 的 draw 方法 shape1.produce(); //获取 Rectangle 的对象,并调用它的 draw 方法 Shape shape2 = shapeFactory.getShape1("RECTANGLE"); //调用 Rectangle 的 draw 方法 shape2.produce(); //获取 Square 的对象,并调用它的 draw 方法 Shape shape3 = shapeFactory.getShape1("SQUARE"); //调用 Square 的 draw 方法 shape3.produce(); } } 

  测试结果

produce Circle! produce Rectangle! produce Square! 

  在工厂模式下,如果需要new什么对象就在shapeFactory.getShape()中传入需要的图形,看似很方便其实潜在这一个问题。当如果需求变了,需求不在是CIRCLE、RECTANGLE、SQUARE这三种图形,而是第四种图形,就需要修改工厂类的getShape()方法,增加一个if判断,这种方式需要修改源代码的方式及其不优雅。因此,引出了我们接下来要讨论的问题,如何通过Java反射的形式动态的获取对象。

三、通过Java反射的方式动态的获取对象

  修改上面工厂模式的工厂类

讯享网public class ShapeFactory { //使用 getShape 方法获取形状类型的对象 public Shape getShape1(String shapeType){ if(shapeType == null){ return null; } if(shapeType.equalsIgnoreCase("CIRCLE")){ return new Circle(); } else if(shapeType.equalsIgnoreCase("RECTANGLE")){ return new Rectangle(); } else if(shapeType.equalsIgnoreCase("SQUARE")){ return new Square(); } return null; } public Shape getShape2(String className){ try { Class clazz = Class.forName(className); Constructor con = clazz.getConstructor(); return (Shape) con.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return null; } } 

  添加新产品类


讯享网

public class Triangle implements Shape { @Override public void produce() { System.out.println("produce Triangle!"); } } 

  测试类修改

讯享网@SpringBootTest public class FactoryTest { @Test public void test2(){ ShapeFactory shapeFactory = new ShapeFactory(); Shape shape1 = shapeFactory.getShape2("com.franky.modules.factory.product.impl.Square"); shape1.produce(); Shape shape2 = shapeFactory.getShape2("com.franky.modules.factory.product.impl.Rectangle"); shape2.produce(); Shape shape3 = shapeFactory.getShape2("com.franky.modules.factory.product.impl.Circle"); shape3.produce(); Shape shape4 = shapeFactory.getShape2("com.franky.modules.factory.product.impl.Triangle"); shape4.produce(); } } 

  控制台打印结果

produce Square! produce Rectangle! produce Circle! produce Triangle! 

  改造后的工厂类,当需要增加新的产品后则不需要再进行修改工厂类。在程序运行过程种,需要调用哪个类就加载哪个类。这就是Java反射的便利之处。

四、Java反射优劣势

  通过上面得例子,我们已经体会到了Java反射在某些方便的便利之处,Java反射除了优势肯定还有劣势,这里我们详细的分析下Java反射的优劣势。

1、优势

  • 增加程序的灵活性,避免将程序写死到代码里
  • 代码简洁,提高代码复用率
  • 破坏类的封装,可以访问类的私有方法、属性;

2、劣势

  • 相比于直接new的方式,Java反射操作的效率会比非反射操作的效率低很多,因为中间需要多个检查和解析步骤,JVM无法进行优化;
  • 反射提高了代码的复杂性,维护代码较为困难;
  • 反射机制使得类的私有属性和方法暴露出来,可能导致其他意外副作用,降低了可移植性。
  • 反射需要运行时权限,在安全管理器下运行时可能不存在。对于在受限安全上下文运行的代码,例如Applet中,这是一个重要的考虑因素;

五、Java反射的使用

  以下是测试使用的类

讯享网@Data @TableName("student") @ApiModel(value="学生实体") public class Student { @TableId(type = IdType.UUID) @ApiModelProperty(value="id") private String id; @ApiModelProperty(value="姓名") private String name; @ApiModelProperty(value="年龄") public String age; @ApiModelProperty(value="年级") private String grade; @ApiModelProperty(value="创建人") private String createBy; @TableField(fill = FieldFill.INSERT) @ApiModelProperty(value="创建时间") private Date createTime; @ApiModelProperty(value="更新人") private String updateBy; @TableField(fill = FieldFill.UPDATE) @ApiModelProperty(value="更新时间") private Date updateTime; @ApiModelProperty(value="所属租户") public String corpCode; @TableLogic @ApiModelProperty(value="删除状态 0正常 1已删除") public String delFlag; public Student() { } public Student(String id, String name) { this.id = id; this.name = name; } private Student(String id, String name, String age, String grade) { this.id = id; this.name = name; this.age = age; this.grade = grade; } private void sayHello(String name) { System.out.println("hello: " + name); } public void sayHi(String name) { System.out.println("hi: " + name); } } 

1、获取Class对象

  获取Class对象的方式有三种,不管哪种方式,都是获取同一个对象。

  • 类明.class 方式获取Class对象
Class clazz1 = Student.class; 
  • 实例.getClass() 方式获取Class对象
讯享网Student student = new Student(); Class clazz2 = student.getClass(); 
  • Class.forName(className) 方式获取Class对象
try { Class clazz3 = Class.forName("com.franky.modules.student.entity.Student"); System.out.println("clazz3: " + clazz3); } catch (ClassNotFoundException e) { e.printStackTrace(); } 

  测试类

讯享网@SpringBootTest public class ReflectTest { @Test public void test(){ // 类明.class 方式获取Class对象 Class clazz1 = Student.class; System.out.println("clazz1: " + clazz1); // 实例.getClass() 方式获取Class对象 Student student = new Student(); Class clazz2 = student.getClass(); System.out.println("clazz2: " + clazz2); // Class.forName(className) 方式获取Class对象 try { Class clazz3 = Class.forName("com.franky.modules.student.entity.Student"); System.out.println("clazz3: " + clazz3); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } 

  控制台输出结果

clazz1: class com.franky.modules.student.entity.Student clazz2: class com.franky.modules.student.entity.Student clazz3: class com.franky.modules.student.entity.Student 

2、通过获取的Class类获取实例对象

  • 通过Class对象调用newInstance()方法,此方法有一定的局限性,只能调用无参构造方法;
讯享网Class clazz1 = Student.class; System.out.println("clazz1: " + clazz1); try { // 通过Class对象调用newInstance()方法 Student student1 = (Student)clazz1.newInstance(); System.out.println(student1.toString()); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } 
  • 通过Constructor构造器调用newInstance()方法,此方法可以调用任意的构造方法;
Class clazz1 = Student.class; try { Constructor constructor = clazz1.getConstructor(String.class, String.class); try { Student student2 = (Student) constructor.newInstance("123", "小米"); System.out.println(student2.toString()); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } catch (NoSuchMethodException e) { e.printStackTrace(); } 

3、获取类中的变量Field

  • Field[] getFields():获取类中所有被public修饰的所有属性;
讯享网Class clazz = Student.class; Field[] fields = clazz.getFields(); 
  • Field getField(String name):根据变量名获取类中的一个变量,该变量必须被public修饰;
Class clazz = Student.class; Field field2 = clazz.getField("age"); 
  • Field[] getDeclaredFields():获取类中所有的变量,但无法获取继承下来的变量;
讯享网Class clazz = Student.class; Field[] fields2 = clazz.getDeclaredFields(); 
  • Field getDeclaredField(String name):根据姓名获取类中的某个变量,无法获取继承下来的变量;
Class clazz = Student.class; Field field1 = clazz.getDeclaredField("name"); 

4、获取类中的方法Method

  • Method[] getMethods():获取类中被public修饰的所有方法;
  • Method getMethod(String name, Class…<?> paramTypes):根据方法名和参数类型获取对应方法,该方法必须被public修饰;
讯享网Class clazz = Student.class; Student student = (Student)clazz.newInstance(); Method method1 = clazz.getMethod("sayHi", String.class); method1.invoke(student,"maomao"); 
  • Method[] getDeclaredMethods():获取所有方法,但无法获取继承下来的方法;
  • Method getDeclaredMethod(String name, Class…<?> paramTypes):根据名字和参数类型获取对应方法,无法获取继承下来的方法,在调用私有方法前,需要先获取权限setAccessible(true);
Class clazz = Student.class; Student student = (Student)clazz.newInstance(); Method method2 = clazz.getDeclaredMethod("sayHello", String.class); method2.setAccessible(true); method2.invoke(student,"caiying"); 

5、获取类中的构造器Constructor

  构造方法归根结底也是方法,除了使用获取Method方法获取构造器外,与此类似Java还提供了获取构造器的独立方法。

  • Constuctor[] getConstructors():获取类中所有被public修饰的构造器;
  • Constructor getConstructor(Class…<?> paramTypes):根据参数类型获取类中某个构造器,该构造器必须被public修饰;
讯享网Class clazz = Student.class; Constructor constructor = clazz.getConstructor(String.class, String.class); Student student = (Student)constructor.newInstance("123", "maomao"); 
  • Constructor[] getDeclaredConstructors():获取类中所有构造器,私有构造方法使用前需要先获取权限setAccessible(true);
  • Constructor getDeclaredConstructor(class…<?> paramTypes):根据参数类型获取对应的构造器,私有构造方法使用前需要先获取权限setAccessible(true);
Class clazz = Student.class; Constructor constructor2 = clazz.getDeclaredConstructor(String.class, String.class, String.class, String.class); constructor2.setAccessible(true); Student student2 = (Student)constructor2.newInstance("456", "caiying", "28", "6"); System.out.println(student2.toString()); 
小讯
上一篇 2025-02-05 23:49
下一篇 2025-03-11 14:31

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/39707.html