目录
一、介绍
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();
}
}
}
输出结果:
需要注意,在使用反射操作属性时,要确保属性可见和有权限,同时也要正确处理异常和数据类型。反射操作虽然灵活,但同时也需要注意性能问题,避免多次重复反射导致性能下降。