Java反射详解

简介: Java反射详解

反射是框架设计的灵魂

(使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码),一切反射的操作都是从类对象开始)

一、反射的概述

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

反射就是把java类中的各种成分映射成一个个的Java对象

例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。

二、反射机制有什么用?

  1. 运行时动态获取类的信息:在编写代码时,对于类的信息是必须在编译时确定的,但在运行时,有时需要根据某些条件,动态获取某个类的信息,这时就可以使用Java中的反射机制。
  2. 动态生成对象:反射机制可以在运行时生成对象,这样就可以根据参数的不同,动态的创建不同的类的实例对象。
  3. 动态调用方法:通过反射机制可以调用类中的方法,不论这些方法是否是公共的,也不论这些方法的参数个数和类型是什么,反射机制都具有这样的能力。
  4. 动态修改属性:利用反射机制可以获取到类中的所有成员变量,并可以对其进行修改。
  5. 实现动态代理:利用反射机制可以实现代理模式,通过代理对象完成原对象对某些方法的调用,同时也可以在这些方法的调用前后做一些额外的处理。

三、Java反射机制的优点

  1. 增加灵活性和扩展性:使用反射机制可以在程序运行时动态加载、修改、创建、调用类和方法等,从而增加了程序的灵活性和可扩展性。
  2. 提高代码的通用性:通过反射机制可以动态的获取类信息,从而可以编写通用的代码,使得不同的类能够以相同的方式来处理。
  3. 规范代码结构:反射机制可以使代码结构清晰明了,减少了代码中的冗余部分。
  4. 实现框架和插件:反射机制在很多框架和插件中都有广泛的应用,比如Spring框架、JUnit测试框架等。
  5. 动态代理:反射机制的另一个重要应用是实现动态代理,可以在不修改原来代码的情况下,通过代理对象对原对象的方法进行增强。

四、反射机制相关的重要的类有哪些?

必须先获得Class才能获取Method、Constructor、Field

Class类

Class代表类的实体,在运行的Java应用程序中表示类和接口。在这个类中提供了很多有用的方法,这里对他们简单的分类介绍。

  • 获得类相关的方法

  • 获得类中属性相关的方法

  • 获得类中构造器相关的方法

  • 获得类中方法相关的方法

接下来,我们已Student实体为实例

package com.ctb.reflect;
/**
 * 学生实体
 * @author biao
 *
 */
public class Student {
  private String sid;
  private String sname;
  public Integer age;
  static{
    System.out.println("加载进jvm中!");
  }
  public Student() {
    super();
    System.out.println("调用无参构造方法创建了一个学生对象");
  }
  public Student(String sid) {
    super();
    this.sid = sid;
    System.out.println("调用带一个参数的构造方法创建了一个学生对象");
  }
  public Student(String sid, String sname) {
    super();
    this.sid = sid;
    this.sname = sname;
    System.out.println("调用带二个参数的构造方法创建了一个学生对象");
  }
  @SuppressWarnings("unused")
  private Student(Integer age) {
    System.out.println("调用Student类私有的构造方法创建一个学生对象");
    this.age = age;
  }
  public String getSid() {
    return sid;
  }
  public void setSid(String sid) {
    this.sid = sid;
  }
  public String getSname() {
    return sname;
  }
  public void setSname(String sname) {
    this.sname = sname;
  }
  public void hello() {
    System.out.println("你好!我是" + this.sname);
  }
  public void hello(String name) {
    System.out.println(name + "你好!我是" + this.sname);
  }
  @SuppressWarnings("unused")
  private Integer add(Integer a, Integer b) {
    return new Integer(a.intValue() + b.intValue());
  }
}

五、获取Class的三种方式

1.Class.forname--应用在jdbc数据库连接中

2.类实例.getclass()---通用增删改

3.类名.class--通用查询

实例:
package com.ctb.reflect;
/**
 * 类类的获取方式
 * 一切反射的操作都是从类对象开始
 * @author biao
 *
 */
public class Demo1 {
  public static void main(String[] args) throws Exception {
    //1.Class.forname--应用在jdbc数据库连接中
    Class<?> forName = Class.forName("com.ctb.reflect.Student");
    System.out.println(forName);
    Student stu=new Student();
    //2.类实例.getclass()---通用增删改
    Class<? extends Student> class1 = stu.getClass();
    System.out.println(class1);
    //3.类名.class--通用查询
     Class<Student> class2 = Student.class;
    System.out.println(class2);
  }
}

输出结果:

六、反射实例化

对象.newInstance()

:newInstance()方法内部实际上调用了无参数构造方法,必须保证无参构造存在才可以。

否则会抛出java.lang.InstantiationException异常。

package com.ctb.reflect;
import java.lang.reflect.Constructor;
/**
 * 反射实例化
 * 添加有参构造器,一定要补一个无参构造器
 * @author biao
 *
 */
public class Demo2 {
  public static void main(String[] args) throws Exception {
    //一切反射从类类开始
    Class<Student> c1=Student.class;
    Student stu=new Student();
    //调用无参构造器反射实例化
    Object o=c1.newInstance();
    System.out.println(o);
    //调用1个参数的构造器反射实例化
    Constructor<Student> ct = c1.getConstructor(String.class);
    Student student = ct.newInstance("5869");
    System.out.println(student);
    //调用2个参数的构造器反射实例化
     Constructor<Student> ct1 = c1.getConstructor(String.class,String.class);
          Student s2 = ct1.newInstance("66744", "小文子");
          System.out.println(s2);
          //getConstructor方法只能获取到公有的构造器对象
          //调用私有化的构造器反射实例化
          Constructor<Student> ct2 = c1.getDeclaredConstructor(Integer.class);
          //打开私有修饰的访问权限
          ct2.setAccessible(true);
          Student ss = ct2.newInstance(89);
          System.out.println(ss);
  }
}

输出结果:

七、反射动态方法调用

Method类方法

实例:
package com.ctb.reflect;
import java.lang.reflect.Method;
/**
 * 反射动态方法调用
 * @author biao
 *
 */
public class Demo3 {
  public static void main(String[] args) throws Exception {
     Student stu = new Student();
          Class c = stu.getClass();
          //反射的无参数方法调用
          //getMethod(?,?)方法名,调用方法要传参数类型
          Method m1 = c.getMethod("嘿嘿");
          //invoke(?,?)类实例,参数值
          Object invoke = m1.invoke(stu);
          System.out.println(invoke);
          //反射的有参数方法调用
          Method m2 = c.getMethod("嘿嘿", String.class);
          System.out.println(m2.invoke(stu, "牛马"));
          //反射的私有化有参数方法调用
          Method m3 = c.getDeclaredMethod("add", Integer.class, Integer.class);
          m3.setAccessible(true);
          System.out.println(m3.invoke(stu, 90, 10));
  }
}

输出结果:

八、反射读写属性

Field类方法

实例:
package com.ctb.reflect;
import java.lang.reflect.Field;
/**
 * 反射读写属性
 * 
 * @author biao
 *
 */
public class Demo4 {
  public static void main(String[] args) throws Exception {
    Student stu = new Student("5499", "酰基");
    stu.age = 3040;
    Class clz = stu.getClass();
    //获取stu实例对象中的所有属性值
    //反射存值
    Field sname = clz.getDeclaredField("sname");
    sname.setAccessible(true);
    sname.set(stu, "犹记");
    //反射获取属性值
    Field[] fields = clz.getDeclaredFields();
    for (Field field : fields) {
      field.setAccessible(true);
      System.out.println(field.getName() + ":" + field.get(stu));
    }
  }
}

输出结果:

注:当对象中存入值后,再次调用set方法存值时会覆盖

九、Java反射机制应用场景

  1. 框架开发:许多流行的Java框架,比如Spring、Hibernate、Struts等,都使用了反射机制,以提供更灵活、可扩展的特性。
  2. 应用程序开发:反射机制常常用于某些需要动态加载或访问类信息的应用程序中,比如动态配置,插件管理等。
  3. 单元测试:JUnit测试框架中,反射机制被广泛应用,可以方便地创建测试对象和调用测试方法。
  4. 动态代理:反射机制可以实现动态代理,实现不改变原来代码的情况下,对原来对象的方法进行增强。
  5. JavaBean工具:JavaBean工具中,使用反射机制可以获取类的属性名、属性值、调用属性的setter和getter方法等信息,方便进行对象的序列化与反序列化操作。


相关文章
|
23天前
|
监控 Java
Java基础——反射
本文介绍了Java反射机制的基本概念和使用方法,包括`Class`类的使用、动态加载类、获取方法和成员变量信息、方法反射操作、以及通过反射了解集合泛型的本质。同时,文章还探讨了动态代理的概念及其应用,通过实例展示了如何利用动态代理实现面向切面编程(AOP),例如为方法执行添加性能监控。
|
1月前
|
Java
Java的反射
Java的反射。
26 2
|
2月前
|
存储 Java
[Java]反射
本文详细介绍了Java反射机制的基本概念、使用方法及其注意事项。首先解释了反射的定义和类加载过程,接着通过具体示例展示了如何使用反射获取和操作类的构造方法、方法和变量。文章还讨论了反射在类加载、内部类、父类成员访问等方面的特殊行为,并提供了通过反射跳过泛型检查的示例。最后,简要介绍了字面量和符号引用的概念。全文旨在帮助读者深入理解反射机制及其应用场景。
34 0
[Java]反射
|
3月前
|
安全 Java 索引
Java——反射&枚举
本文介绍了Java反射机制及其应用,包括获取Class对象、构造方法、成员变量和成员方法。反射允许在运行时动态操作类和对象,例如创建对象、调用方法和访问字段。文章详细解释了不同方法的使用方式及其注意事项,并展示了如何通过反射获取类的各种信息。此外,还介绍了枚举类型的特点和使用方法,包括枚举的构造方法及其在反射中的特殊处理。
74 9
Java——反射&枚举
|
2月前
|
安全 Java 测试技术
🌟Java零基础-反射:从入门到精通
【10月更文挑战第4天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
29 2
|
3月前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
2月前
|
IDE Java 编译器
java的反射与注解
java的反射与注解
17 0
|
3月前
|
Java 程序员 编译器
Java的反射技术reflect
Java的反射技术允许程序在运行时动态加载和操作类,基于字节码文件构建中间语言代码,进而生成机器码在JVM上执行,实现了“一次编译,到处运行”。此技术虽需更多运行时间,但广泛应用于Spring框架的持续集成、动态配置及三大特性(IOC、DI、AOP)中,支持企业级应用的迭代升级和灵活配置管理,适用于集群部署与数据同步场景。
|
3月前
|
存储 安全 Java
扫盲java基础-反射(一)
扫盲java基础-反射(一)
|
3月前
|
Java
扫盲java基础-反射(二)
扫盲java基础-反射(二)