一、介绍
JavaEE中的反射(Reflection)指的是通过Java代码动态地获取类、方法、属性等信息的机制。JavaEE应用程序通常需要处理大量的类和对象,有时候我们需要在代码中动态地获取这些类、对象的信息或者动态地创建这些对象,这就需要利用反射机制。
1.前言
JavaEE(Java Enterprise Edition)是Java平台上的一种开发规范和标准。它包含了一系列API和技术,可以帮助开发者构建企业级的Java应用程序。反射是Java语言中的一种机制,它允许程序在运行时动态地获取类的信息、创建类的对象、调用类的方法、访问/修改类的属性等。JavaEE中的一些技术,如Servlet和JSP,也使用了反射机制。通过反射,我们可以在运行时动态地获取类的信息,从而使得编程更加灵活和便捷。在JavaEE开发中,反射是一种非常重要的技术,它可以帮助我们实现很多高级功能。对于JavaEE开发者来说,掌握反射技术是十分必要的。
2.作用
JavaEE开发中的反射机制主要有以下几个作用:
- 动态获取类的信息:JavaEE应用程序通常需要处理大量的类和对象。有时候,我们需要在代码中获取一个类的名字、父类、接口、构造函数列表、方法列表、属性列表等信息。通过反射机制,我们可以在运行时动态地获取这些信息,从而使得程序更加灵活和可扩展。
- 动态创建对象:有时候,我们不知道程序运行时需要创建哪些类的对象。通过反射机制,我们可以在运行时动态地创建对象,并调用它们的方法或修改它们的属性。
- 动态调用方法:JavaEE开发中的许多技术(如Servlet和JSP)都使用了反射机制来动态地调用方法。通过反射机制,我们可以在运行时动态地调用一个对象的方法,而不需要提前知道这个方法的具体名称、参数类型和返回值类型。
- 动态修改属性值:有时候,我们需要在程序运行时动态修改对象的属性值。通过反射机制,我们可以在程序运行时得到一个对象的属性列表,然后像访问和修改普通属性一样来处理它们。
3.概述
反射机制极大地提高了JavaEE应用程序的灵活性和可扩展性。利用反射机制,我们可以在程序运行期间动态地获取类、创建对象、调用方法、访问属性等,这使得我们可以在不知道对象类型、方法名等信息的情况下动态地调用方法,或者动态地获取属性值。比如在Servlet、JSP等技术中就大量使用了反射机制。同时,反射机制也为一些高级技术的实现提供了基础,如动态代理、AOP、ORM等。总之,反射是JavaEE开发中非常常用的技术之一,熟练掌握反射机制是JavaEE开发人员必须的技能之一。
二、类类
1.类类的作用
以下五类是JavaEE中反射的类类核心
1. Class 类:Class 类是 Java 反射机制的核心。所有 Java 类都有一个对应的 Class 对象用于反射。通过 Class 类,我们可以获取一个类的名字、父类、接口、构造函数列表、方法列表、属性列表等。我们还可以通过 Class 类创建对象实例,或者动态调用类的方法。
2. Constructor 类:Constructor 类用于描述 Java 类中的构造函数。通过 Constructor 类,我们可以获取构造函数的参数类型列表,以及创建该类的对象实例。
3. Method 类:Method 类用于描述 Java 类中的方法。通过 Method 类,我们可以获取方法的名字、参数类型列表、返回值类型等信息,以及动态地调用方法。
4. Field 类:Field 类用于描述 Java 类中的属性。通过 Field 类,我们可以获取属性的名字、类型、修饰符等信息,以及动态地访问和修改属性值。
5. Modifier 类:Modifier 类用于描述 Java 类中修饰符的信息。通过 Modifier 类,我们可以获取修饰符的名称、值以及与修饰符相关的一些操作。
通过使用这些类,我们可以在 JavaEE 开发中实现许多高级功能,比如动态创建对象、动态调用方法、动态修改属性值等。同时,我们也可以利用反射机制来调试、测试、分析和优化 Java 应用程序。
2.类类的读取
例如:现在创建一个人类[实体对象]代码如下
package com.SAME_LOVE.reflective; /** * @author SAME_LOVE * @com.SAME_LOVE.reflective * @Person(说明):人类[实体对象] */ public class Person { private String pid; private String name; private Integer age; static { System.out.println("已加载到jvm中"); } public Person() { super(); System.out.println("已调用无参构造方法创建了一个人类对象"); } public Person(String pid) { super(); System.out.println("已调用带一个参数构造方法创建了一个人类对象"); this.pid = pid; } public Person(String pid, String name, Integer age) { super(); System.out.println("已调用多参构造方法创建了一个人类对象"); this.pid = pid; this.name = name; this.age = age; } @SuppressWarnings("unused") private Person(Integer age) { this.age = age; System.out.println("已调用Person类中带一个参数并且私有的构造方法创建了一个人类对象"); } @SuppressWarnings("unused") private Person(String name,Integer age) { this.name = name; this.age = age; System.out.println("已调用Person类中多参数并且私有的构造方法创建了一个人类对象"); } public void hello() { System.out.println("你好!我是" + this.name); } public void hello(String name) { System.out.println(name + ";你好!我是" + this.name); } @SuppressWarnings("unused") private Integer add(Integer a, Integer b) { return new Integer(a.intValue() + b.intValue()); } @Override public String toString() { return "Person [pid=" + pid + ", name=" + name + ", age=" + age + "]"; } public String getPid() { return pid; } public void setPid(String pid) { this.pid = pid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
2.1.Class.forName("");
通过类的全限定名获取Class对象:
//实例化 Person p = new Person(); try { //类的读取 Class c1 = Class.forName("com.SAME_LOVE.reflective.Person"); // System.out.println(c1); } catch (ClassNotFoundException e) { e.printStackTrace(); }
2.2.实例化.getClass();
通过类的实例获取Class对象:
//实例化 Person p = new Person(); Class c2 = p.getClass(); System.out.println(c2);
2.3.类.class
通过类字面常量获取Class对象:
//实例化 Person p = new Person(); Class c3 = Person.class; System.out.println(c3);
以上测试后输出的结果皆为:
三、反射实例化
通过反射机制可以实现在运行时根据类的名称动态地创建对象实例,实例化过程中可以指定构造函数及其参数。
综上Person类的所以代码进行测试
1.无参构造
// 实例化 Person p = new Person(); Class c = null; try { // 类的读取 c = Class.forName("com.SAME_LOVE.reflective.Person"); // System.out.println(c1); } catch (ClassNotFoundException e) { e.printStackTrace(); } // 1.调用无参构造方法反射实例化 try { //强制类型转换为实际对象 Person p1 = (Person) c.newInstance(); System.out.println(p1); } catch (Exception e) { e.printStackTrace(); }
输出结果:
2.有一参构造
// 实例化 Person p = new Person(); Class c = null; try { // 类的读取 c = Class.forName("com.SAME_LOVE.reflective.Person"); // System.out.println(c1); } catch (ClassNotFoundException e) { e.printStackTrace(); } // 2.调用有一个参数构造方法反射实例化 //parameterTypes:代表参数类别的Class,例如:String.class try { Constructor cr2= c.getConstructor(String.class); //强制类型转换为实际对象 Person p2 = (Person) cr2.newInstance("p001"); System.out.println(p2); } catch (Exception e) { e.printStackTrace(); }
输出结果:
3.多参构造
// 实例化 Person p = new Person(); Class c = null; try { // 类的读取 c = Class.forName("com.SAME_LOVE.reflective.Person"); // System.out.println(c1); } catch (ClassNotFoundException e) { e.printStackTrace(); } // 3.调用有多个参数构造方法反射实例化 // parameterTypes:代表参数类别的Class,例如:String.class try { Constructor cr3= c.getConstructor(String.class,String.class,Integer.class); Person p3 = (Person) cr3.newInstance("p001","ikun",18); System.out.println(p3); } catch (Exception e) { e.printStackTrace(); }
输出结果:
4.有一参且私有构造
// 实例化 Person p = new Person(); Class c = null; try { // 类的读取 c = Class.forName("com.SAME_LOVE.reflective.Person"); // System.out.println(c1); } catch (ClassNotFoundException e) { e.printStackTrace(); } //4.调用有一个参数且私有的构造方法反射实例化 try { Constructor cr4=c.getDeclaredConstructor(Integer.class); //打开私有权限 cr4.setAccessible(true); //反射实体 Person p4 = (Person)cr4.newInstance(18); System.out.println(p4); } catch (Exception e) { e.printStackTrace(); }
输出结果:
5.有多且私有构造
// 实例化 Person p = new Person(); Class c = null; try { // 类的读取 c = Class.forName("com.SAME_LOVE.reflective.Person"); // System.out.println(c1); } catch (ClassNotFoundException e) { e.printStackTrace(); } //5.调用多参数且私有的构造方法反射实例化 try { Constructor cr5=c.getDeclaredConstructor(String.class,Integer.class); //打开私有权限 cr5.setAccessible(true); //反射实体 Person p5 = (Person)cr5.newInstance("ikun",18); System.out.println(p5); } catch (Exception e) { e.printStackTrace(); }
输出结果:
在上述代码中,使用getConstructor()方法获取一个包含两个参数的构造方法,然后使用newInstance()方法来实例化类对象,并传入相应的参数。
需要注意,在使用反射实例化类对象时,要确保类对象可以被实例化,必须有可访问的构造方法,同时也要正确处理异常。反射操作虽然灵活,但同时也需要注意性能问题,避免多次重复反射导致性能下降。
四、反射方法
Java反射机制可以通过Method类来获取类中的方法,包括公有方法和私有方法,获取到方法后,可以使用invoke()方法来调用方法。
综上Person类的所以代码进行测试。
1.无参
Class c = Person.class; try { Person p = (Person) c.newInstance(); //name:方法名称,parameterTypes:这个方法的参数类型 Method m1 = c.getMethod("hello"); //obj:类实例,args:参数值,invoke:方法返回值 Object invoke = m1.invoke(p); System.out.println(invoke); } catch (Exception e) { e.printStackTrace(); }
输出结果:
2.有参
Class c = Person.class; try { Person p = (Person) c.newInstance(); // name:方法名称,parameterTypes:这个方法的参数类型 Method m2 = c.getMethod("hello", String.class); // obj:类实例,args:参数值,invoke:方法返回值 Object Object invoke = m2.invoke(p, "p001"); System.out.println(invoke); } catch (Exception e) { e.printStackTrace(); }
输出结果:
3.私有且多参
Class c = Person.class; try { Person p = (Person) c.newInstance(); // name:方法名称,parameterTypes:这个方法的参数类型 Method m3 = c.getDeclaredMethod("add", Integer.class,Integer.class); //打开私有权限 m3.setAccessible(true); // obj:类实例,args:参数值,invoke:方法返回值 Object invoke = m3.invoke(p,10,15); System.out.println(invoke); } catch (Exception e) { e.printStackTrace(); }
输出结果:
Java反射机制可以通过Method类来获取类中的方法,包括公有方法和私有方法,获取到方法后,可以使用invoke()方法来调用方法。
五、反射属性
Java反射机制可以通过Field类来获取类中的属性信息,包括公有属性和私有属性,获取到属性后可以进行读取或者操作。
属性指的是类中的字段,也就是成员变量。Field类提供了许多方法,包括获取属性名称、获取属性类型、获取属性的访问修饰符、获取属性值、设置属性值等方法。通过这些方法可以得到属性的详细信息,包括修饰符、类型、值等。
综上Person类的所以代码进行测试。
1.获取属性
Person p = new Person("p001","ikun",18); Class c = p.getClass(); System.out.println(p); System.out.println("-------------------------"); //调用getDeclaredFields获取Person的所有属性名称 Field[] fields = c.getDeclaredFields(); try { //循环这个属性集合 for (Field f : fields) { //打开私有权限 f.setAccessible(true); //getName():获取属性名称,get:根据实例化对象获取属性值 System.out.println(f.getName()+":"+f.get(p)); } } catch (Exception e) { e.printStackTrace(); }
输出结果:
2.获取属性修改
package com.SAME_LOVE.reflective; import java.lang.reflect.Field; /** * @author SAME_LOVE * @com.SAME_LOVE.reflective * @Demo04(说明):反射读取属性 */ public class Demo04 { public static void main(String[] args) { Person p = new Person("p001","ikun",18); Class c = p.getClass(); System.out.println(p); System.out.println("+++++++修改属性值+++++++"); try { /*getDeclaredField("name"); * 根据属性名称返回属性 */ Field namefield = c.getDeclaredField("name"); //打开私有权限 namefield.setAccessible(true); //重写修改后的值 //obj:实例化对象 //value:修改后的值 namefield.set(p, "小卡拉米"); } catch (Exception e1) { e1.printStackTrace(); } System.out.println("-------------------------"); //调用getDeclaredFields获取Person的所有属性名称 Field[] fields = c.getDeclaredFields(); try { //循环这个属性集合 for (Field f : fields) { //打开私有权限 f.setAccessible(true); //getName():获取属性名称,get:根据实例化对象获取属性值 System.out.println(f.getName()+":"+f.get(p)); } } catch (Exception e) { e.printStackTrace(); } } }
输出结果:
需要注意,在使用反射操作属性时,要确保属性可见和有权限,同时也要正确处理异常和数据类型。反射操作虽然灵活,但同时也需要注意性能问题,避免多次重复反射导致性能下降。