Java反射机制入门:解锁运行时类信息的秘密

反射技术:

  • 其实就是对类进行解剖的技术
  • 类中有什么?
  • 构造方法
    • 成员方法
    • 成员变量

结论:反射技术就是把一个类进行了解剖,然后获取到 构造方法、成员变量、成员方法


反射技术的应用案例:

  • idea
  • 框架技术:Spring

想要使用反射技术有一个必备条件

  • Class对象
  • 原因:.class文件由类加载器读取并创建Class对象。Class对象中存储了.class文件中的内容:构造方法、成员变量、成员方法

反射技术的作用

使用反射技术,可以对类进行解剖,可以获取到类中的:构造方法、成员变量、成员方法

  • 构造方法: 可以创建对象
  • 成员方法: 可以调用执行
  • 成员变量: 赋值、取值

反射技术的作用:

  • 不用使用new关键字,就可以创建对象
  • 不用使用"对象名.方法"形式,就可以调用方法
  • 不用使用"对象名.属性"形式,就可以给属性赋值、取值
  • 通常在类中属性,都被修饰为private(私有的:外部不能访问)
  • 反射技术,可以做到对私有成员进行操作

 

"cn.itcast.pojo.Student" stu = new cn.itcast.pojo.Student();


给一个字符串:"cn.icast.pojo.Student"

创建一个对象:?????   //使用new做不到  
           使用反射技术可以实现

给一个Student.class

程序在运行中,不能停止, 动态的获取一个Student.class
    //使用反射技术,可v

小结

反射技术 :对类进行解剖的技术

反射技术的作用:可以不通过传统方式,来实现类的实例化、方法的调用

  • 实现的提前:需要使用Class对象

反射:Class类

路径

  1. Class类
  2. 获取Class类对象的方式
  3. Class类中的常用方法

Class类

  • Class就是用来描述正在运行的java类型
  • Class类的实例表示Java中任何正在运行的类型,每一个类型都有与之对应的Class对象
    • 比如:类,接口,枚举,注解,数组,基本数据类型,void 都有与之对应的Class对象
类名.class
接口名.class
int.class
boolean.class
array.class   

获取Class对象

获取Class类对象的方式有3种:

方式一:类型名.class   //Student.class
方式二:对象.getClass()  //对象名.getClass()
方式三:Class.forName(String className) //className是全路径类名 = 包名+类型名
//方式1:类型名.class
//应用场景: 当类名明确时,可以直接使用"类名.class"
Class clz = String.class 
Class clz = int.class 
Class clz = double.class

//方式2:对象.getClass()
//应用场景:通常是应用方法中
 public void method(Student stu){
    Class clz = stu.getClass();   
 } 

//方式3: Class.forName("类的全名称");//带有包名的类
//应用场景: 通常使用在读取配置文件中的类型
pro.properties文件
--------------文件内容------------------    
className=cn.icast.pojo.Student   
---------------------------------------   
//代码实现    
ResourceBundler r = ResourceBundler.getBundler("pro");
String className = r.getString("className");//"cn.icast.pojo.Student"

Class StudentClass = Class.forName(className);//className="cn.icast.pojo.Student" 

//当获取到Class对象了,就可以对类进行解剖了

Class类中的常用方法

String getSimpleName()  // 获得类名字符串:类名
String getName()   // 获得类全名:包名+类名
T newInstance() // 创建Class对象关联类的对象 (前提:类中有一个无参构造方法)

//示例:
      Studentod类    cn.itcast.pojo.Student     //public Student(){}

      Class stuClass = Student.class;
      Object obj = stuClass.newInstance();//调用Student()  创建Student对象

      Student stu = (Student) obj;

代码实现

public class Test01 {

    @Test
    public void testMethod3() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class stuClass = Class.forName("com.itheima.cls.demo2.Student");

        Student stu = (Student) stuClass.newInstance();

        stu.study();
    }



    @Test
    public void testMethod2() throws IllegalAccessException, InstantiationException {
        Student stu =new Student();

        //对象名.getClass()
        Class studentClass = stu.getClass();

        Student student = (Student) studentClass.newInstance();

        student.study();
    }


    @Test
    public void testMethod1() throws IllegalAccessException, InstantiationException {
        // 类型名.class
        Class studentClass = Student.class;
        //System.out.println(studentClass);

        System.out.println("带有包名的类:"+studentClass.getName());
        System.out.println("类名:"+studentClass.getSimpleName());

        //实例化Student对象
        Object obj = studentClass.newInstance();
        Student stu = (Student) obj;
        stu.age=20;
        stu.name="张三";
        System.out.println(stu.name+"==="+stu.age);
        stu.study();
    }
}

获取Class对象的方式:

  1. 类型名.class //明确了具体的类型时,直接使用:类名.class
  2. 对象名.getClass() //当方法中传递的对象时,使用:对象名.getClass()
  3. Class类中的静态方法:forName("带有包名的类") //从配置文件中读取到类的全名称时

反射:构造器

路径

  1. Constructor类
  2. 获取构造器Constructor对象的方式
  3. Constructor类中常用方法

构造方法对应的类型:  Constructor类型
字段:Field
方法:Method

Constructor类

  • 代表构造方法(构造器)
  • 类中的每一个构造方法都是一个Constructor类的对象

反射技术中构造器的目的:

  • 获得Constructor对象来创建类的对象
大白话:不使用new关键字,通过Constructor来创建对象

获取Constructor对象的方式

Constructor对象的获取和Class类中方法有关:

Constructor[] getConstructors()
        //获得类中的所有构造方法对象,只能获得public的

Constructor[] getDeclaredConstructors()
        //获得类中的所有构造方法对象
        //可以是public、protected、(默认)、private修饰符的构造方法    


Constructor getConstructor( Class... parameterTypes)
        //根据参数类型获得对应的Constructor对象   获取public修饰的
        //只能获得public修饰的构造方法
/*示例: Student       public Student(String name, int age)    public Student(int age) 
        Class stuClass = Student.class;
        //根据给定的参数类型,来获取匹配的构造器对象
        Constructor c = stuClass.getConstructor( String.class , int.class );
*/  


Constructor getDeclaredConstructor(Class... parameterTypes)
        //根据参数类型获得对应的Constructor对象
        //可以是public、protected、默认、private修饰符的构造方法

Constructor类常用方法

T newInstance(Object... initargs)
     //根据指定的参数创建对象
/*
        Class stuClass = Student.class;
        //根据给定的参数类型,来获取匹配的构造器对象
        Constructor c = stuClass.getConstructor( String.class , int.class );
        //使用构造器对象,来实例化Student
        c.newInstance( "张三", 22 );//Student(String name, int age)

        //无参构造
        Constructor c = stuClass.getConstructor();
        Student stu = (Student) c.newInstance();
*/    


void setAccessible(true)//应用场景:仅适用于访问有权限检查的成员
   //设置"暴力反射" ——是否取消权限检查,true取消权限检查,false表示不取消

代码实现:

public class Test1 {
    @Test
    public void testMethod1() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
       //获取构造器的步骤
        /*1、先获取到Class对象
          2、使用Class对象中的方法,获取Constructor对象
          3、使用Constructor对象,实例化类
       */
        //获取Class对象(Student.class)
        Class stuClass = Student.class;

        //获取Constructor对象: public Student()
        Constructor con1 = stuClass.getConstructor();

        System.out.println(con1);

        Student stu = (Student)con1.
                       ();
        stu.name="小崔";
        System.out.println(stu.name);
    }
}

Constructor类:

  • 代表类中的一个构造方法

获取Constructor类的方式:

//获取public修饰的构造方法
Constructor getConstructor(Class... parameterTypes)


//获取非public修饰的方法
Constructor getDeclaredConstructor(Class... parameterTypes)
Object newInstance(Object... param)  //利用构造器对象,实例化自定义对象

void setAccessible(true) //消除JVM对权限的检查操作 (一次性的。只是对当前操作去除)    

反射:使用构造器创建对象

路径

  1. 案例:使用无参构造器创建对象
  2. 案例:使用有参构造器创建对象
  3. 案例:使用私有构造器创建对象
  4. 案例:使用私有构造器创建对象

案例:使用无参构造器创建对象

@Test
    public void testMethod1() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取Class对象(Student.class)
        Class stuClass = Student.class;

        //利用Class对象,来获取构造器对象
        Constructor con = stuClass.getConstructor();//方法中的参数为可变参数,可以不传递值

        //使用Constructor对象中的方法,来实例化Student类对象
        Student stu = (Student) con.newInstance();//方法中的参数是可变参数

        stu.study();
    }

案例:使用有参构造器创建对象

//有参构造方法
    @Test
    public void testMethod2() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取Class对象(Student.class)
        Class stuClass = Student.class;

        //public Student(String name, int age, String gender)
        //获取带有参数的构造器对象
        //参数:是用来设置构造方法中参数的类型是什么
        Constructor con = stuClass.getConstructor(String.class, int.class, String.class);

        //实例化有参构造方法
        //参数:要传递给Student(String name, int age, String gender)的数据
        Student stu = (Student) con.newInstance("熊大", 22, "男");

        //调用对象中的方法
        stu.study();
    }

案例:使用私有构造器创建对象

@Test
    public void testMethod3() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取Class对象(Student.class)
        Class stuClass = Student.class;

        // private Student(String name)
        //获取私有构造器对象
        Constructor con = stuClass.getDeclaredConstructor(String.class);

        //当需要对私有成员操作时,需要先取消JVM对访问权限的检查操作
        con.setAccessible(true);//暴力破解(取消权限检查) //仅在当前次取消

        //使用私有构造器,实例化Student对象
        Student stu = (Student) con.newInstance("文平");

        System.out.println(stu.name);
        stu.study();
    }

反射:方法

路径

  1. Method类
  2. 获取Method对象的方式
  3. Method类常用方法

Method

Method类

  • 代表一个成员方法
    • 每一个成员方法都是一个Method类的对象

反射技术中使用Method的目的:

  • 通过Method对象来调用成员方法

获取Method对象的方式

Method对象的获取和Class类中方法有关:

Method[] getMethods();
    //获得当前类和其父类中的所有public成员方法对象,返回数组

Method[] getDeclaredMethods();
    //获得当前类中的所有成员方法对象,返回数组
    //只获得本类的,包括public、protected、默认、private的

Method getMethod(String name,Class...args);
    //根据方法名和参数类型获得对应的成员方法对象,只能获得public的
    //参数说明:
             name : 类中方法的名字
             args : 方法中参数类型的Class     例:int.class     

Method getDeclaredMethod(String name,Class...args);
    //根据方法名和参数类型获得对应的成员方法对象,包括public、protected、(默认)、private的

Method类常用方法

//使用方法对象,调用对象中的方法执行(入栈执行)
Object invoke(Object obj, Object... args) 
    // obj: 对象   //"对象名.方法"
    // args:调用方法时传递的实参
//返回值: Object类型      

void setAccessible(true)
    // 设置"暴力访问"  ——是否取消权限检查,true取消权限检查,false表示不取消

代码实现:

//获取Method对象的步骤:
1、先获取Class对象
2、使用Class对象,获取Method对象
3、使用Method对象,执行方法

public class Test01 {
    @Test
    public void testMethod1() throws ClassNotFoundException {
        //获取Class对象
        Class stuClass  = Class.forName("com.itheima.method.demo1.Student");

        //使用Class对象,获取Method对象
        Method[] methods = stuClass.getMethods();//获取本类及父类中所有的public方法
        for (Method m : methods){
            System.out.println(m);
        }
    }
    @Test
    public void testMethod2() throws ClassNotFoundException {
        //获取Class对象
        Class stuClass  = Class.forName("com.itheima.method.demo1.Student");

        //使用Class对象,获取Method对象
        Method[] methods = stuClass.getDeclaredMethods();//获取本类中所有方法(包含私有)
        for (Method m : methods){
            System.out.println(m);
        }
    }
}    

反射:方法调用

路径

  1. 案例:调用无参无返回值的方法
  2. 案例:调用有参有返回值的方法
  3. 案例:调用私有方法
  4. 案例:调用静态方法

案例:调用无参无返回值的方法

 @Test
    public void testMethod1() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取Class对象
        Class stuClass = Student.class;

        //因为在调用Method时,需要传递Student对象
        Constructor con = stuClass.getConstructor();
        Student stu = (Student)con.newInstance();

        //获取public void study()方法的对象
        Method method = stuClass.getMethod("study");

        //使用Method对象 执行study()方法
        method.invoke( stu );
    }

案例:调用有参有返回值的方法

/有参有返回值
    @Test
    public void testMethod2() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取Class对象
        Class stuClass = Student.class;

        //因为在调用Method时,需要传递Student对象
        Constructor con = stuClass.getConstructor();
        Student stu = (Student)con.newInstance();

        //获取public String sayHello(String name)方法的Method对象
        Method method = stuClass.getMethod("sayHello", String.class);

        //调用method方法
       Object result = method.invoke(stu,"波波");

        System.out.println(result);
    }

案例:调用私有方法

//私有方法
    @Test
    public void testMethod3() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
        //获取Class对象
        Class stuClass = Student.class;

        //因为在调用Method时,需要传递Student对象
        Constructor con = stuClass.getConstructor();
        Student stu = (Student)con.newInstance();

        //获取 private void eat(String name)方法的Method对象
        Method method = stuClass.getDeclaredMethod("eat", String.class);

        //去除JVM对当前次权限的检查
        method.setAccessible(true);

        //执行method方法
        method.invoke(stu,"红烧肉");
    }

案例:调用静态方法

//静态方法
    @Test
    public void testMethod4() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //获取Class对象
        Class stuClass = Student.class;

        //静态方法的调用不需要对象。"类名.静态方法()"
        //获取public static void sleep()方法的Method对象
        Method method = stuClass.getMethod("sleep");

        //执行静态方法
        method.invoke(null);//不需要传递对象(null就表示执行静态方法)
    }

Method对象的使用步骤:

1、获取Class对象

2、基于Class对象,获取Method对象

//有参方法
Method method = Class对象.getMethod("方法名",参数1类型.class,参数2类型.class ...);
//无参方法
Method method = class对象.getMethod("方法名");

3、使用Method对象,执行方法

//调用非静态方法
method对象.invoke(实例对象,方法中需要的实参)

//调用静态方法
method对象.invoke(null,方法中需要的实参)    

反射的作用案例演示

  • 作用反射是框架的灵魂!框架的底层一定会用到反射技术。
  • 需求:要把猫的睡觉方法 变成 狗的吃饭方法
  • 效果:使用反射+Properties完成配置文件。把需要修改的灵活的内容写在配置文件中,代码不需要做任何的改动。
    • 案例演示
public class Dog {

    public void eat(){
        System.out.println("狗爱吃肉");
    }

    public void sleep(){
        System.out.println("狗睡觉流口水");
    }

}

public class Cat {

    public void eat(){
        System.out.println("猫爱吃鱼");
    }

    public void sleep(){
        System.out.println("猫睡觉打呼噜");
    }
}

  public class Demo {
      public static void main(String[] args) throws Exception{
          //不使用反射
          //需求:   要把猫的睡觉方法  变成  狗的吃饭方法
          //Dog d = new Dog();
          //d.eat();

          //使用反射
          //properties
          Properties pro = new Properties();
          //load():可以把文件中的键值对读取到集合中
          FileReader fr = new FileReader("day21\\aaa.txt");
          pro.load(fr);

          //通过键获取值
          String cn = pro.getProperty("className");
          String mn = pro.getProperty("methodName");

          //获取字节码对象
          Class c = Class.forName(cn);
          //获取空参构造
          Constructor con = c.getConstructor();
          //执行构造方法
          Object o = con.newInstance();
          //获取方法
          Method m = c.getMethod(mn);
          //执行方法
          m.invoke(o);

      }
  }

  配置文件:
      className=com.itheima_05.Cat
      methodName=sleep

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/882665.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络安全-ssrf

目录 一、环境 二、漏洞讲解 三、靶场讲解 四、可利用协议 4.1 dict协议 4.2 file协议 4.3 gopher协议 五、看一道ctf题吧(长亭的比赛) 5.1环境 5.2开始测试 ​编辑 一、环境 pikachu,这里我直接docker拉取的,我只写原…

基于vue框架的传统文化传播网站设计与实现f7r43(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能:用户,文化类型,传统文化 开题报告内容 基于Vue框架的传统文化传播网站设计与实现开题报告 一、研究背景 在全球化加速的今天,各国文化相互交融,但也面临着传统文化被边缘化的风险。中国拥有五千年文明史&#…

【通俗易懂介绍OAuth2.0协议以及4种授权模式】

文章目录 一.OAuth2.0协议介绍二.设计来源于生活三.关于令牌与密码的区别四.应用场景五.接下来分别简单介绍下四种授权模式吧1.客户端模式1.1 介绍1.2 适用场景1.3 时序图 2.密码模式2.1 介绍2.2 适用场景2.3时序图 3.授权码模式3.1 介绍3.2 适用场景3.3 时序图 4.简化模式4.1 …

数据的表示和存储 第3讲 C语言中的整数

深耕AI ​互联网行业 算法研发工程师 概括 本讲主要介绍了C语言中的整数表示。 无符号整数能够表示的最大值比带符号整数要大。带符号整数使用补码来表示,补码的运算系统是一种模运算系统,能够实现加减运算的统一。在C语言中,如果一个表达式…

利用F.interpolate()函数进行插值操作

函数简介 功能: 利用插值方法,对输入的张量数组进行上\下采样操作,换句话说就是科学合理地改变数组的尺寸大小,尽量保持数据完整。 torch.nn.functional.interpolate(input, sizeNone, scale_factorNone, modenearest, align_c…

【赵渝强老师】K8s的DaemonSets控制器

DaemonSet控制器相当于在节点上启动了一个守护进程。通过使用DaemonSet可以确保一个Pod的副本运行在 Node节点上。如果有新的Node节点加入集群,DaemonSet也会自动给新加入的节点增加一个Pod的副本;反之,当有Node节点从集群中移除时&#xff0…

EdgeRoute_镜像烧录

1. EdgeRouter 概述 EdgeRouter Lite 是由 Ubiquiti Networks 公司生产的一款高性能网络路由器,适用于家庭和小型办公环境。它的尺寸为200 x 90 x 30 mm,重量为345克,配备了双核500 MHz的MIPS64处理器,并带有硬件加速功能&#x…

MySQL_数据类型简介

课 程 推 荐我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈虚 拟 环 境 搭 建 :&#x1…

Vue使用Vue Router路由:开发单页应用

1、路由基础 在单页 Web 应用中,整个项目只有一个 HTML 文件,不同视图(组件的模块)的内容都是在同一个页面中渲染的。当用户切换页面时,页面之前的跳转都是在浏览器端完成的,这时就需要使用前端路由。 路…

APP自动化中 ADB Monkey用法

一、monkey是干什么的? 我们可以使用monkey做手机端性能的压力测试,稳定性测试 二、monkey在使用的时候,他的运行特性 monkey默认配置下执行,会在手机中随机的点击或者轻触我们的手机中应用,不过这个时候&#xff0…

Cortex-M7核心寄存器

参考内容:Cortex-M7编程手册 文章目录 软件执行的处理器模式和权限级别处理器模式软件执行的权限级别 栈Stacks核心寄存器Core registers通用寄存器General-purpose registers链接寄存器Link register程序计数器 Program counter程序状态寄存器Program status regis…

PMP--二模--解题--91-100

文章目录 14.敏捷91、 [单选] 在敏捷团队完成三次迭代之后,项目经理确定团队在这三次迭代中的平均速度是30个故事点。还有292个故事点来完成项目的剩余部分。团队需要多少次额外的迭代才能完成项目? 9.资源管理92、 [单选] 项目经理前往另一个国家执行最…

python yield用法

1 yield关键字 yield在函数中的功能类似于return,不同的是yield每次返回结果之后函数并没有退出,而是 每次遇到yield关键字后返回相应结果,并保留函数当前的运行状态,等待下一次的调用。如果 一个函数需要多次循环执行一个动作&am…

【自动驾驶】控制算法(九)深度解析车辆纵向控制 | 从算法基础到 Carsim 仿真实践

写在前面: 🌟 欢迎光临 清流君 的博客小天地,这里是我分享技术与心得的温馨角落。📝 个人主页:清流君_CSDN博客,期待与您一同探索 移动机器人 领域的无限可能。 🔍 本文系 清流君 原创之作&…

『功能项目』QFrameWorkBug关联Slot(插槽)【67】

我们打开上一篇66QFrameWorkBug拖拽功能的项目, 本章要做的事情是关联插槽Slot 修改脚本:UISlot.cs 修改脚本:UGUICanvas.cs 此时关联Slot已经完成 接下来的文章内容: 1.QFrameWork扔到地上UGUI 2.位置存储功能 3.点击名称寻…

Python可迭代对象(2)

目录 3。字典 字典的构造 字典的添加和修改 字典推导式的使用 以上全部代码编译结果展示 字典复习 4。集合(set) 集合的创建 集合的运算 集合的添加和删除元素 以上全部代码的编译结果 序列解包(Sequence unpacking) 3。字典 字典的构造 #字…

【Linux】nginx连接前端项目

文章目录 一、项目编译1.编译文件2.dist文件 二、Linux nginx配置三、启动nginx 一、项目编译 1.编译文件 2.dist文件 二、Linux nginx配置 在Xshell软件中,点击CtrlAltF进入文件传输找到地址:/usr/local/nginx/html将dist文件传入 找到nginx.conf&…

R包:VennDiagram韦恩图

加载R包 library(VennDiagram)数据 # Prepare character vectors v1 <- c("DKK1", "NPC1", "NAPG", "ERG", "VHL", "BTD", "MALL", "HAUS1") v2 <- c("SMAD4", "DKK1…

【计算机网络 - 基础问题】每日 3 题(十九)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏&…

【Python】curl命令、Api POST导入cURL、python直接使用cURL

文章目录 一、浏览器复制cURL二、API POST直接使用cURL创建接口三、python直接使用cURL构建网络请求四、curl命令详解语法选项实例 cURL是一种命令行工具&#xff0c;常用于通过各种协议&#xff08;如HTTP、HTTPS、FTP等&#xff09;传输数据。它的名字来源于"Client URL…