反射-JavaEE

简介: 反射-JavaEE

一、介绍

JavaEE中的反射(Reflection)指的是通过Java代码动态地获取类、方法、属性等信息的机制。JavaEE应用程序通常需要处理大量的类和对象,有时候我们需要在代码中动态地获取这些类、对象的信息或者动态地创建这些对象,这就需要利用反射机制。

1.前言

JavaEE(Java Enterprise Edition)是Java平台上的一种开发规范和标准。它包含了一系列API和技术,可以帮助开发者构建企业级的Java应用程序。反射是Java语言中的一种机制,它允许程序在运行时动态地获取类的信息、创建类的对象、调用类的方法、访问/修改类的属性等。JavaEE中的一些技术,如Servlet和JSP,也使用了反射机制。通过反射,我们可以在运行时动态地获取类的信息,从而使得编程更加灵活和便捷。在JavaEE开发中,反射是一种非常重要的技术,它可以帮助我们实现很多高级功能。对于JavaEE开发者来说,掌握反射技术是十分必要的。

2.作用

JavaEE开发中的反射机制主要有以下几个作用:

  1. 动态获取类的信息:JavaEE应用程序通常需要处理大量的类和对象。有时候,我们需要在代码中获取一个类的名字、父类、接口、构造函数列表、方法列表、属性列表等信息。通过反射机制,我们可以在运行时动态地获取这些信息,从而使得程序更加灵活和可扩展。
  2. 动态创建对象:有时候,我们不知道程序运行时需要创建哪些类的对象。通过反射机制,我们可以在运行时动态地创建对象,并调用它们的方法或修改它们的属性。
  3. 动态调用方法:JavaEE开发中的许多技术(如Servlet和JSP)都使用了反射机制来动态地调用方法。通过反射机制,我们可以在运行时动态地调用一个对象的方法,而不需要提前知道这个方法的具体名称、参数类型和返回值类型。
  4. 动态修改属性值:有时候,我们需要在程序运行时动态修改对象的属性值。通过反射机制,我们可以在程序运行时得到一个对象的属性列表,然后像访问和修改普通属性一样来处理它们。

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();
    } 
  }
}

输出结果:

需要注意,在使用反射操作属性时,要确保属性可见和有权限,同时也要正确处理异常和数据类型。反射操作虽然灵活,但同时也需要注意性能问题,避免多次重复反射导致性能下降。

目录
相关文章
|
8月前
|
Java
JavaEE之反射(详解)2
JavaEE之反射(详解)2
27 0
|
21天前
|
监控 Java 开发者
掌握 Java 反射和动态代理
【4月更文挑战第19天】Java反射和动态代理提供强大功能和灵活性。反射允许运行时检查和操作类,获取类信息、动态调用方法,但可能带来性能损失和降低代码可读性。动态代理则用于创建代理对象,实现透明性和横切关注点分离,常用于日志、权限检查等。两者结合能实现更复杂功能。掌握这些技术能提升代码的灵活性和可扩展性,但也需注意性能和可读性。通过学习和实践,能更好地构建高效软件系统。
|
8月前
|
XML 安全 Java
【javaSE】 反射与反射的使用
【javaSE】 反射与反射的使用
|
4月前
|
安全 Java API
Java中的反射(通过反射获取类的结构、invoke方法、获取注解)
Java中的反射(通过反射获取类的结构、invoke方法、获取注解)
|
10月前
|
JSON 安全 Java
|
6月前
|
Java 数据库连接 数据库
JavaEE之反射
JavaEE之反射
49 0
|
8月前
|
Java 数据库连接 数据库
JavaEE之反射(详解)1
JavaEE之反射(详解)1
48 0
|
8月前
|
缓存 Java
java通过反射获取加了某个注解的所有的类
java通过反射获取加了某个注解的所有的类
|
10月前
|
Java API Spring
|
存储 前端开发 Java
【Java】反射、注解、动态代理总结(一)
【Java】反射、注解、动态代理总结
【Java】反射、注解、动态代理总结(一)