深入了解Java反射机制

简介: 深入了解Java反射机制

一、前言

1.什么是反射机制

        Java反射指的是Java语言在运行时动态地获取类信息、构造类对象、调用对象方法以及访问或修改对象属性的能力。Java反射机制允许Java程序在运行期间检查其本身的结构并获取类属性、方法和构造函数的信息,也可以动态地创建类的实例、调用其方法和访问其属性。JDK 中 java.lang.Class 类,就是为了实现反射提供的核心类之一。

2.为什么要使用反射

1.获取任意类的名称、package信息、所有属性、方法、注解、类型、类加载器(类类)等

2.获取任意对象的属性,并且能改变对象的属性

3.调用任意对象的方法

4.判断任意一个对象所属的类

5.实例化任意一个类的对象

二、使用反射

接下来的所有操作用Student类来演示

package com.xw;
public class Student {
  private String sid;
  private String sname;
  public Integer age;
  static{
    System.out.println("静态代码块加载中。。。");
  }
  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());
  }
}

1.什么是类类(类加载器)

       在Java中,类加载器是一种重要的机制,它负责把 Java 字节码文件(.class文件) 加载到内存中,并将其转换成 Java 类的运行时表示形式。Java类加载器按照加载的方式和顺序可以分为三类:Bootstrap Class Loader(启动类加载器)、Extention Class Loader(扩展类加载器)和App Class Loader(应用程序类加载器)。

      类加载器是Java虚拟机(JVM)的一部分,主要用于实现Java程序的动态扩展和代码的动态加载。类加载器可以加载本地的class文件,也可以从网络或其他JVM中获取class文件进行加载。通过Java反射和类加载器机制,开发人员可以动态地创建对象、调用类的方法、访问类的属性等等,从而实现软件组件的灵活性和可扩展性。    

注意:类加载器并不等同于类,它只负责将类的字节码文件加载到内存中,虚拟机会根据字节码文件实例化和加载类。类加载器按照加载的顺序和层次关系形成一个树状结构,父类加载器可以委托子类加载器来加载类,在默认情况下,父类加载器可以看到其子类加载器所加载的类,但反过来则不行,这样可以使得类在整个JVM中得到合适的共享。

2.获取类类(类加载器)

Class.forName

        //第一种:Class.forName 参数是类的全路径名
    Student stu=new Student();
    Class forName = Class.forName("com.xw.Student");
    System.out.println(forName);
      //打印结果:class com.xw.Student

主要作用于连接sql,加载驱动。

类名.class

//第二种:类名.class
    Class StudentClass =Student.class;
    System.out.println(StudentClass);
//打印结果:class com.xw.Student

实例化对象.getClass

//第三种:对象.getClass
        Student stu=new Student();
    Class objectClass=stu.getClass();
    System.out.println(objectClass);
//打印结果:class com.xw.Student

注意

①所有反射先从类类(类加载器)开始,我们首先需要通过获取类类(类加载器),来加载目标类的字节码文件,然后解析字节码文件并生成类的元数据信息,最终使我们能够使用Java反射机制来操作该类的实例。

反射机制默认调用无参构造器来创建类的实例,但是并不是说所有的类都必须有无参构造器。如果一个类没有定义无参构造器,那么反射机制就无法直接使用Class.newInstance()方法来创建该类的实例,因为该方法会默认调用无参构造器,如果该类没有定义无参构造器,就会抛出InstantiationException异常。

③如果一个类没有定义无参构造器,我们可以通过使用其他的构造器来创建类的实例。例如,我们可以使用Constructor.newInstance()方法来调用指定的构造器来创建类的实例。

3.反射实例

反射实例要用到的方法

方法 描述
newInstance() 用于创建一个类的实例。用 newInstance() 方法时,该类必须有可访问的无参构造方法,否则会抛出异常。
getConstructo()

获取指定类中的公共构造器,可以通过这个构造器来创建该类的实例。

注意:该方法需要传入一个Class数组作为参数,用于指定构造器的参数类型列表。

getDeclaredConstructor() 获取指定类中声明的构造器。与getConstructor() 方法不同的是,getDeclaredConstructor() 方法可以获取到指定类中的私有构造器。
 setAccessible() 用于设置一个 AccessibleObject 对象(包括构造器、方法、字段等)的访问标志为 true,使得在访问该对象时被访问的实体(例如:Java 虚拟机)可以忽略 JAVA 语言访问控制检查。

没有无参构造器的错误

Class<Student> c0=Student.class;
  Student newInstance = c0.newInstance();
  System.out.println(newInstance);
  //java.lang.NoSuchMethodException: com.xw.Student.<init>()

无参构造器

  Class<Student> c1=Student.class;
  Student newInstance2 = c1.newInstance();
  System.out.println(newInstance2);
  //com.xw.Student@7852e922

一个参数的构造器

  Class<Student> c2=Student.class;
  Constructor<Student> cr2 = c2.getConstructor(String.class);
  Student newInstance3 = cr2.newInstance("01");
  System.out.println(newInstance3);
  //com.xw.Student@182decdb

两个参数的构造器

Class<Student> c3=Student.class;
  Constructor<Student> cr3 = c3.getConstructor(String.class,String.class);
  Student newInstance4 = cr3.newInstance("01","xw");
  System.out.println(newInstance4);
  //com.xw.Student@182decdb

私有的有参构造器

Class<Student> c4=Student.class;
  Constructor<Student> cr4 = c4.getDeclaredConstructor(Integer.class);
  cr4.setAccessible(true);
  Student newInstance5 = cr4.newInstance(2);
  System.out.println(newInstance5);
  //com.xw.Student@182decdb

4.反射动态方法调用

如果你看懂了反射实例那么反射动态方法只是换个方法那么简单。

反射动态方法要用到的方法

方法 描述
getMethod(name, parameterTypes)

获取某个类中的公共方法。这个方法属于 Class 类的实例方法,因此必须先获取到该类的 Class 对象,然后调用 getMethod() 方法。

name:方法名 parameterTypes:类型

invoke(obj, args)

调用一个对象的方法,并且可以向该方法传递参数。

obj:类实例 args:参数

getDeclaredMethod(name, parameterTypes) 

 获取某个类中声明的方法,不包括父类中声明的方法。这个方法属于 Class 类的实例方法,因此必须先获取到该类的 Class 对象,然后调用 getDeclaredMethod() 方法。

name:方法名 parameterTypes:类型

调用无参方法

// 所有反射先从类类开始
    Class<Student> c = Student.class;
    Student stu = new Student();
        Method m1 = c.getMethod("hello");
        Object invoke = m1.invoke(stu);
     System.out.println(invoke);
    /*
     * 你好!我是null null
     */

调用有参方法

// 所有反射先从类类开始
    Class<Student> c = Student.class;
    Student stu = new Student();
        Method m2 = c.getMethod("hello", String.class);
    Object invoke2 = m2.invoke(stu, "xw");
     System.out.println(invoke2);
    /*
     * xw你好!我是null null
     */

调用私有方法

// 所有反射先从类类开始
    Class<Student> c = Student.class;
    Student stu = new Student();
        Method m3 = c.getDeclaredMethod("add", Integer.class,Integer.class);
    m3.setAccessible(true);
    Object invoke3 = m3.invoke(stu, 1,2);
    System.out.println(invoke3);
    //打印结果:3

5.通过反射进行读写属性

反射读写属性要用的方法

方法 描述
getDeclaredField() 获取类中指定名称的成员变量,不包括父类中的成员变量。
getDeclaredFields() 获取类中全部的成员变量,不包括父类中的成员变量。
get() 获取类的成员变量的值的方法。这个方法属于 Field 类的实例方法,因此必须先获取到该类的 Field 对象,然后调用 get() 方法。
getName() 用于获取成员变量名称的方法,可以获取所有可访问的类成员(包括私有或受保护成员)。
set() 设置类的成员变量值的方法,可以设置公共成员变量和私有成员变量的值。需要注意的是。注意:在设置私有成员变量的值时,需要先使用 setAccessible(true) 方法将可访问性设置为 true。

根据属性名称获取指定实例的值

        // 实例化student类
    Student stu = new Student("01", "xw");
    // 获取类类
    Class cc = Student.class;
        Field declaredField = cc.getDeclaredField("sname");
    declaredField.setAccessible(true);
    Object object = declaredField.get(stu);
    String name = declaredField.getName();
    System.out.println(name);
     System.out.println(object);
        //打印结果:xw

获取实例的所有属性名称以及属性值

        // 实例化student类
    Student stu = new Student("01", "xw");
    // 先获取类类
    Class cc = Student.class;
        Field[] field = cc.getDeclaredFields();
    for (Field field2 : field) {
      field2.setAccessible(true);
      System.out.println(field2.getName() + "   " + field2.get(stu));
      /*
       * sid 01 
       * sname xw 
       * age null
       * 
       */
    }

修改实例student的sname的属性值

        // 实例化student类
    Student stu = new Student("01", "xw");
    // 先获取类类
    Class cc = Student.class;
      Field declaredField2 = cc.getDeclaredField("sname");
    declaredField2.setAccessible(true);
    declaredField2.set(stu, "xw帅逼");
    Object object2 = declaredField2.get(stu);
    System.out.println(object2);
        //打印结果:xw帅逼

觉得有用的话记得点个赞哦!!


相关文章
|
9天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
33 2
|
14天前
|
Java 编译器
探索Java中的异常处理机制
【10月更文挑战第35天】在Java的世界中,异常是程序运行过程中不可避免的一部分。本文将通过通俗易懂的语言和生动的比喻,带你了解Java中的异常处理机制,包括异常的类型、如何捕获和处理异常,以及如何在代码中有效地利用异常处理来提升程序的健壮性。让我们一起走进Java的异常世界,学习如何优雅地面对和解决问题吧!
|
1月前
|
存储 算法 Java
Java HashSet:底层工作原理与实现机制
本文介绍了Java中HashSet的工作原理,包括其基于HashMap实现的底层机制。通过示例代码展示了HashSet如何添加元素,并解析了add方法的具体过程,包括计算hash值、处理碰撞及扩容机制。
|
25天前
|
XML 安全 Java
Java反射机制:解锁代码的无限可能
Java 反射(Reflection)是Java 的特征之一,它允许程序在运行时动态地访问和操作类的信息,包括类的属性、方法和构造函数。 反射机制能够使程序具备更大的灵活性和扩展性
35 5
Java反射机制:解锁代码的无限可能
|
13天前
|
Java 数据库连接 开发者
Java中的异常处理机制及其最佳实践####
在本文中,我们将探讨Java编程语言中的异常处理机制。通过深入分析try-catch语句、throws关键字以及自定义异常的创建与使用,我们旨在揭示如何有效地管理和响应程序运行中的错误和异常情况。此外,本文还将讨论一些最佳实践,以帮助开发者编写更加健壮和易于维护的代码。 ####
|
19天前
|
安全 IDE Java
Java反射Reflect机制详解
Java反射(Reflection)机制是Java语言的重要特性之一,允许程序在运行时动态地获取类的信息,并对类进行操作,如创建实例、调用方法、访问字段等。反射机制极大地提高了Java程序的灵活性和动态性,但也带来了性能和安全方面的挑战。本文将详细介绍Java反射机制的基本概念、常用操作、应用场景以及其优缺点。 ## 基本概念 ### 什么是反射 反射是一种在程序运行时动态获取类的信息,并对类进行操作的机制。通过反射,程序可以在运行时获得类的字段、方法、构造函数等信息,并可以动态调用方法、创建实例和访问字段。 ### 反射的核心类 Java反射机制主要由以下几个类和接口组成,这些类
40 2
|
23天前
|
存储 缓存 安全
🌟Java零基础:深入解析Java序列化机制
【10月更文挑战第20天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
24 3
|
24天前
|
安全 Java UED
深入理解Java中的异常处理机制
【10月更文挑战第25天】在编程世界中,错误和意外是不可避免的。Java作为一种广泛使用的编程语言,其异常处理机制是确保程序健壮性和可靠性的关键。本文通过浅显易懂的语言和实际示例,引导读者了解Java异常处理的基本概念、分类以及如何有效地使用try-catch-finally语句来处理异常情况。我们将从一个简单的例子开始,逐步深入到异常处理的最佳实践,旨在帮助初学者和有经验的开发者更好地掌握这一重要技能。
22 2
|
26天前
|
Java 数据库连接 开发者
Java中的异常处理机制####
本文深入探讨了Java语言中异常处理的核心概念,通过实例解析了try-catch语句的工作原理,并讨论了finally块和throws关键字的使用场景。我们将了解如何在Java程序中有效地管理错误,提高代码的健壮性和可维护性。 ####
|
27天前
|
Java
Java中的反射机制与应用实例
【10月更文挑战第22天】Java作为一门面向对象的编程语言,提供了丰富的特性来支持对象的创建、操作和交互。其中,反射机制是Java的一项核心特性,它允许程序在运行时动态地获取类的信息、创建对象、调用方法、访问属性等。本文将从三个部分探讨Java中的反射机制及其应用实例:一是反射机制的基本概念和原理;二是反射机制在Java中的应用场景;三是通过实例深入理解反射机制的使用方法和技巧。
19 4
下一篇
无影云桌面