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

输出结果:

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

目录
相关文章
|
供应链 监控 物联网
未来交织:新兴技术趋势与跨领域应用探索
【4月更文挑战第20天】 在数字化浪潮不断推进的当下,新兴技术如区块链、物联网(IoT)、虚拟现实(VR)等正在重塑我们的工作和生活方式。本文将深入探讨这些技术的发展趋势,并分析它们在不同领域的应用场景。区块链技术以其不可篡改和去中心化的特性,正在金融、供应链管理等领域展现巨大潜力。物联网作为连接万物的桥梁,其智能化和自动化能力正被广泛应用于智慧城市、健康监测等环境。而虚拟现实技术则在娱乐、教育和远程工作等方面提供了沉浸式体验。通过综合分析这些新兴技术的融合与创新,我们预见一个互联互通、更加智能的未来。
用Python实现批量下载文件
用Python实现批量下载文件
|
10月前
|
自然语言处理 搜索推荐 安全
国产CRM系统推荐:助力企业数字化转型
随着企业数字化转型加速,国产CRM系统凭借高性价比、本地化服务和灵活定制能力,成为众多企业的首选。本文对比推荐了几款主要的国产CRM系统,包括销售易、神州云动、八骏科技、纷享销客、悟空CRM等,分析其功能优势、服务支持及适用场景。销售易适合中大型企业,提供全面解决方案;神州云动强调全流程支持和客户数据管理;八骏科技注重全方位客户管理和数据分析;纷享销客则适合中小型企业,强调移动办公和社交化营销;悟空CRM以轻量化设计和简单操作赢得中小企业青睐。选择指南建议企业根据规模、预算、行业特点及系统集成需求,选择最适合的CRM系统,助力业绩高质量增长。
|
数据挖掘 Linux iOS开发
Pandas
【7月更文挑战第4天】Pandas
797 59
|
数据可视化 数据挖掘 关系型数据库
招聘信息数据分析及可视化|以51JOB为例进行
招聘信息数据分析及可视化|以51JOB为例进行
732 0
|
SQL 关系型数据库 MySQL
mysql数据库日常 ---mysql数据库基本操作
mysql数据库日常 ---mysql数据库基本操作
132 0
|
存储 块存储 对象存储
带你读《存储漫谈:Ceph原理与实践》——1.2.2 无中心架构
带你读《存储漫谈:Ceph原理与实践》——1.2.2 无中心架构
|
Java 测试技术 Maven
SpringBoot 3.0 新特性,内置声明式 HTTP 客户端
从 Spring 6 和 Spring Boot 3 开始,Spring 框架支持将远程 HTTP 服务代理成带有特定注解的 Java http interface。类似的库,如 OpenFeign 和 Retrofit 仍然可以使用,但 http interface 为 Spring 框架添加内置支持。
1404 1
SpringBoot 3.0 新特性,内置声明式 HTTP 客户端
Linux系列——修改主机名与IP地址,实现可直接ping主机名
Linux系列——修改主机名与IP地址,实现可直接ping主机名
|
存储 Linux Windows
数据结构——二叉树 1.0
✅<1>主页:我的代码爱吃辣 📃<2>知识讲解:数据结构——二叉树 🔥<3>创作者:我的代码爱吃辣 ☂️<4>开发环境:Visual Studio 2022 🏡<5>系统环境:windows 10 💬<6>前言:今天来学习一下,数据结构中树以及二叉树的一些相关概念。