Java反射概述

news2024/11/17 7:47:41

2 反射

2.1 反射概述

在这里插入图片描述

  • Java反射机制:是指在运行时去获取一个类的变量和方法信息。然后通过获取到的信息来创建对象,调用方法的一种机制。由于这种动态性,可以极大的增强程序的灵活性,程序不用在编译期就完成确定,在运行期仍然可以扩展

2.2 反射获取Class类的对象

  • 我们要想通过反射去使用一个类,首先我们要获取到该类的字节码文件对象,也就是类型为Class类型的对象这里我们提供三种方式获取Cass类型的对象
    • 1、使用类的class属性来获取该类对应的Class对象。举例: Student.class将会返回Student类对应的Class对象

    • 2、调用对象的getClass()方法, 返回该对象所属类对应的Class对象
      该方法是Object类中的方法,所有的Java对象都可以调用该方法

    • 3、使用Class类中的静态方法forName(StringclassName), 该方法需要传入字符串参数,该字符串参数的值是某个类的全路径,也就是完整包名的路径

package test;

public class Demo {
    public static void main(String[] args) throws ClassNotFoundException {
        //1、使用类的class属性来获取该类对应的Class对象
        Class<Student> c1 = Student.class;
        System.out.println(c1); //class test.Student

        Class<Student> c2 = Student.class;
        System.out.println(c1 == c2); //true;一个类只有一个字节码文件对象

        //2、调用对象的getClass()方法, 返回该对象所属类对应的Class对象
        Student s = new Student();
        Class<? extends Student> c3 = s.getClass();
        System.out.println(c1 == c3); //true

        //3、使用Class类中的静态方法forName(StringclassName)
        Class<?> c4 = Class.forName("test.Student");
        System.out.println(c1 == c4); //true
    }
}

2.3 反射获取构造方法并使用

  • Class类中用于获取构造方法的方法
方法名说明
Constructor<?>[] getConstructors()返回所有公共构造方法对象的数组
Constructor<?> [] getDeclaredConstructors [dɪˈkleəd]返回所有构造方法对象的数组
Constructor<T> getConstructor(Class<?>...parameterTypes)返回单个公共构造方法对象
Constructor<T> getDeclaredConstructor(Class<?> ...parameterTypes)返回单个构造方法对象
  • Constructor类中用来创建对象的方法
方法名说明
T newInstance(Object…initargs)根据指定的构造方法创建对象
package test;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;


public class Demo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取Class对象
        Class<?> c = Class.forName("test.Student");

        //1,Constructor<?>[] getConstructors() 	返回所有公共构造方法对象的数组
        Constructor<?>[] cons1 = c.getConstructors();
        for(Constructor con:cons1) {
            System.out.println(con);
//            public test.Student(java.lang.String,int,java.lang.String)
//            public test.Student()
        }
        System.out.println("--------");

        //2,Constructor<?> [] getDeclaredConstructors 	返回所有构造方法对象的数组
        Constructor<?>[] cons2 = c.getDeclaredConstructors();
        for(Constructor con:cons2) {
            System.out.println(con);
//            public test.Student(java.lang.String,int,java.lang.String)
//            test.Student(java.lang.String,int)
//            private test.Student(java.lang.String)
//            public test.Student()
        }
        System.out.println("--------");

        /*
        一、首先把这个类的带包的字符串路径传给forName()方法得到字节码文件Class对象c
        二、c调用getConstructors()得到单个的构造方法对象con1
        三、通过con1调用newInstance()创建一个对象,这就叫反射*/

        //3,Constructor<T> getConstructor(Class<?>...parameterTypes) 	返回单个公共构造方法对象
        //参数是:你要获得的构造方法的参数个数和数据类型对应字节码文件
        Constructor<?> con1 = c.getConstructor();

        //Constructor提供了一个类的单个构造方法信息和访问权限
        //5,T newInstance(Object…initargs) 	根据指定的构造方法创建对象
        Object obj1 = con1.newInstance();
        System.out.println(obj1); //Student{name='null', age=0, address='null'}
    }
}
  • 案例1:
    在这里插入图片描述
package test;


import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Demo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //一、首先把这个类的带包的字符串路径传给Class类的forName()方法得到字节码文件Class对象c
        Class<?> c = Class.forName("test.Student");

        //public Student(String name, int age, String address)
        // 二、c调用getConstructor()得到单个的构造方法对象con1
        Constructor<?> con = c.getConstructor(String.class, int.class, String.class);//基本数据类型int也可以通过.class得到对应class类型

        // 三、通过con调用newInstance()创建一个对象,这就叫反射
        Object obj = con.newInstance("小白",10, "成都");
        System.out.println(obj); //Student{name='小白', age=10, address='成都'}
    }
}
  • 案例2
    在这里插入图片描述
package test;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Demo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //一、首先把这个类的带包的字符串路径传给forName()方法得到字节码文件Class对象c
        Class<?> c = Class.forName("test.Student");

        //private Student(String name)
        //二、通过c调用getConstructor()创建无参构造方法对象
        Constructor<?> con = c.getDeclaredConstructor(String.class);

        //三、通过con调用newInstance()创建一个对象
//        Object obj = con.newInstance("小黑");
//        System.out.println(obj); //IllegalAccessException:没法访问异常:private修饰的私有构造方法

        //暴力反射:public void setAccessible(boolean flag):值为true,取消访问检查
        con.setAccessible(true);
        Object obj = con.newInstance("小黑");
        System.out.println(obj); //Student{name='小黑', age=0, address='null'}
    }
}

2.4 反射获取成员变量并使用

  • Class类中用于获取成员变量的方法
方法名说明
Field[ ] getFields()返回所有公共成员变量对象的数组
Field[ ] getDeclaredFields()返回所有成员变量对象的数组
Field getField(String name)返回单个公共成员变量对象
Field getDeclaredField(String name)返回单个成员变量对象
  • Field类中用于给成员变量赋值的方法
方法名说明
void set(Object obj, Object value)给obj对象的成员变量赋值为value
package test;


import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

public class Demo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        //获取Class对象
        Class<?> c = Class.forName("test.Student");

        //1,Field[] getFields() 	返回所有公共成员变量对象的数组
        Field[] fields1 = c.getFields();
        for(Field field:fields1) {
            System.out.println(field);
            //public java.lang.String test.Student.address
        }
        System.out.println("--------");

        //2,Field[ ] getDeclaredFields() 	返回所有成员变量对象的数组
        Field[] fields2 = c.getDeclaredFields();
        for(Field field:fields2) {
            System.out.println(field);
//            private java.lang.String test.Student.name
//            int test.Student.age
//            public java.lang.String test.Student.address
        }
        System.out.println("--------");

        /* 
         一、首先把这个类的带包的字符串路径传给forName()方法得到字节码文件Class对象c
         二、通过c调用getField()得到成员变量对象addressField
         三、addressField调用set()方法给obj对象的address赋值*/
        
        //3,Field getField(String name) 	返回单个公共成员变量对象
        Field addressField = c.getField("address");
        System.out.println(addressField);
        //public java.lang.String test.Student.address
        
        //获取无参构造方法创建对象
        Constructor<?> con = c.getConstructor();
        Object obj = con.newInstance();
        //5,void set(Object obj, Object value) 	给obj对象的成员变量赋值为value
        addressField.set(obj,"成都"); //给obj的成员变量addressField》address赋值为成都
        System.out.println(obj); //Student{name='null', age=0, address='成都'}
    }
}
  • 案例
    在这里插入图片描述
package test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

public class Demo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        //一、首先把这个类的带包的字符串路径传给forName()方法得到字节码文件Class对象c
        Class<?> c = Class.forName("test.Student");

        //二、通过c调用getConstructor()创建无参构造方法对象
        Constructor<?> con = c.getConstructor();

        //三、通过con调用newInstance()创建一个对象
        Object obj = con.newInstance();

        //四、通过c调用getDeclaredField()得到成员变量对象
        Field nameField = c.getDeclaredField("name");
        nameField.setAccessible(true); //取消私有变量的访问检查

        //五、成员变量对象调用set()方法给obj对象的成员变量赋值
        nameField.set(obj,"小黑");

        Field ageField = c.getDeclaredField("age");
        ageField.setAccessible(true);
        ageField.set(obj,10);

        Field addressField = c.getDeclaredField("address");
        addressField.setAccessible(true);
        addressField.set(obj,"成都");

        System.out.println(obj); //Student{name='小黑', age=10, address='成都'}
    }
}

2.5 反射获取成员方法并使用

  • Class类中获取成员方法的方法
方法名说明
Method[ ] getMethods()返回所有公共成员方法对象的数组,包括继承的
Method[ ] getDeclaredMethods()返回所有成员方法对象的数组,不包括继承的
Method getMethod(String name, Class<?> … parameterTypes)返回单个公共成员方法对象
Method getDeclaredMethod(String name, Class<?> … parameterTypes)返回单个成员方法对象
  • Method类中用于调用成员方法的方法
方法名说明
Object invoke(Object obj, Objet… args)调用obj对象的成员方法,参数是args,返回值是Object类型
package test;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Demo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取Class对象
        Class<?> c = Class.forName("test.Student");

        //1,Method[ ] getMethods() 	返回所有公共成员方法对象的数组,包括继承的
        Method[] methods1 = c.getMethods();
        for(Method method:methods1) {
            System.out.println(method);
//            public java.lang.String test.Student.toString()
//            public void test.Student.method1()
//            public void test.Student.method3()
//            public void test.Student.method2()
//            public final void java.lang.Object.wait() throws java.lang.InterruptedException
//            public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
//            ...
        }
        System.out.println("---------");

        //2,Method[ ] getDeclaredMethods() 	返回所有成员方法对象的数组,不包括继承的
        Method[] methods2 = c.getDeclaredMethods();
        for(Method method:methods2) {
            System.out.println(method);
//            public java.lang.String test.Student.toString()
//            private void test.Student.function()
//            public void test.Student.method1()
//            public void test.Student.method3()
//            public void test.Student.method2()
        }

        //3,Method getMethod(String name, Class<?> … parameterTypes) 	返回单个公共成员方法对象
        Method m = c.getMethod("method1");

        //获取无参构造方法并创建对象
        Constructor<?> con = c.getConstructor();
        Object obj = con.newInstance();

        //5,Object invoke(Object obj, Objet… args) 	调用obj对象的成员方法,参数是args,返回值是Object类型
        //第一个Object:返回值类型;obj:对象;args:方法需要的参数
        m.invoke(obj); //method1
    }
}
  • 案例
    在这里插入图片描述

  • Student类

package test;

public class Student {
    //成员变量:一个私有、一个默认、一个公共
    private String name;
    int age;
    public String address;

    //构造方法:一个私有、一个默认、两个公共
    public Student() {
    }

    private Student(String name) {
        this.name = name;
    }

    Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Student(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    //成员方法:一个私有,四个公共
    private void function() {
        System.out.println("function");
    }

    public void method1() {
        System.out.println("method1");
    }

    public void method2(String s) {
        System.out.println("method2:" + s);
    }

    public String method3(String s, int i) { return s + "," + i; }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }
}
  • 测试类
package test;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Demo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //一、首先把这个类的带包的字符串路径传给forName()方法得到字节码文件Class对象c
        Class<?> c = Class.forName("test.Student");

        //二、通过c调用getConstructor()创建无参构造方法对象
        Constructor<?> con = c.getConstructor();

        //三、通过con调用newInstance()创建一个对象
        Object obj = con.newInstance();

        //四、通过字节码文件对象调用getMethod()方法得到method方法对象
        Method m1 = c.getMethod("method1");

        Method m2 = c.getMethod("method2", String.class);

        Method m3 = c.getMethod("method3", String.class, int.class);

        Method m4 = c.getDeclaredMethod("function");

        //五、通过method方法对象调用invoke()方法
        m1.invoke(obj); //method1

        m2.invoke(obj,"小黑"); //method2:小黑

        Object o = m3.invoke(obj, "小白", 10);
        System.out.println(o); //小白,10

        m4.setAccessible(true);
        m4.invoke(obj); //function
    }
}

2.6 案例

2.6.1案例1:通过反射往ArrayList<Integer>集合中,添加字符串数据

package test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

public class Demo {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        ArrayList<Integer> array = new ArrayList<>();

//        array.add("小黑"); 报错

        Class<? extends ArrayList> c = array.getClass();

        Method m = c.getMethod("add", Object.class); //因为Object是泛型没有指定数据类型

        m.invoke(array, "小黑");
        m.invoke(array, "小黑");
        m.invoke(array, "小黑");

        System.out.println(array); //[小黑, 小黑, 小黑]
    }
}

2.6.2 案例2:通过配置文件运行类中的方法

  • Student类
package test;

public class Student {
    public void study() {
        System.out.println("好好学习天天向上");
    }
}
  • class.txt配置文件
className=test.Student
methodName=study
  • 测试类
package test;

import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class Demo {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //加载数据
        Properties prop = new Properties();
        FileReader fr = new FileReader("E:\\test\\Demo\\class.txt");
        prop.load(fr);
        fr.close();

        System.out.println(prop); //{methodName=study, className=test.Student}

        String className = prop.getProperty("className");
        String methodName = prop.getProperty("methodName");

        //通过反射来使用
        Class<?> c = Class.forName(className); //test.Student
        Constructor<?> con = c.getConstructor();
        Object obj = con.newInstance();

        Method m = c.getMethod(methodName);//study

        m.invoke(obj); //好好学习天天向上
        //class.txt中只需要改文件路径和方法名
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

企业的知识文档管理系统需要注重什么?安全和共享能力很重要!

编者按&#xff1a;本文指出了企业的文档管理系统比较注重的能力&#xff0c;并从知识共享和文档安全两方面介绍了老厂商天翎是如何在这块实践的。关键词&#xff1a;知识共享&#xff0c;知识安全&#xff0c;标签分类&#xff0c;智能检索&#xff0c;资料分享&#xff0c;在…

element ui 下拉菜单组件 结合springboot 实现省市区简易三级联动 动态查询 并修改地点的省市区

目录 前言&#xff1a; 一.数据库表结构&#xff1a; 二.下拉菜单组件 2.1 效果展示 2.2下拉菜单的组件代码&#xff1a; 前言&#xff1a; 本篇博客&#xff0c;通过官网的学习&#xff0c;实现下拉菜单动态数据的传递与点击事件&#xff0c;如果只是按部就班的按照官网来…

29岁从事功能测试被辞,面试2个月都找不到工作吗?

最近一个28岁老同学联系我&#xff0c;因为被公司辞退&#xff0c;找我倾诉&#xff0c;于是写下此文。 他是14年二本毕业&#xff0c;在我的印象里人特别懒&#xff0c;不爱学习&#xff0c;专业不好&#xff0c;毕业前因为都没找到合适工作&#xff0c;直接去创业了&#xf…

03:入门篇 - CTK Plugin Framework 基本原理

作者: 一去、二三里 个人微信号: iwaleon 微信公众号: 高效程序员 CTK Plugin Framework 技术是面向 C++ 的动态模型系统。该系统允许插件之间的松散耦合,并且提供了设计良好的方式来进行功能和数据的交互。此外,它没有预先对插件施加限制,这样就可以很容易地将插件的相关…

研报精选230217

目录 【行业230217毕马威】奢侈品行业新气象【行业230217国信证券】医药生物行业2023年2月投资策略&#xff1a;持续关注疫后复苏和创新两大主线【行业230217国金证券】航空锻造&#xff1a;稳定格局筑专业化壁垒&#xff0c;顺势而为拓产业链深度【个股230217西南证券_招商轮船…

javaEE 初阶 — 传输层 TCP 协议 中的延迟应答与捎带应答

文章目录1. 延迟应答2. 捎带应答TCP 工作机制&#xff1a;确认应答机制 超时重传机制 连接管理机制 滑动窗口 流量控制与拥塞控制 1. 延迟应答 延时应答 也是提升效率的机制&#xff0c;也是在滑动窗口基础上搞点事情。 滑动窗口的关键是让窗口大小大一点&#xff0c;传输…

LabVIEW监控实时嵌入式目标上的CPU和内存使用情况

LabVIEW监控实时嵌入式目标上的CPU和内存使用情况NI实时&#xff08;RT&#xff09;控制器上有不同的用于监测CPU和内存使用情况的不同选项。可用内存量取决于多个因素&#xff0c;包括已安装的软件和用户应用程序内存要求。本文将介绍从Windows操作系统访问此信息的不同方法&a…

盘点23大厂互联网秋招技术岗薪资!

2023届秋招形式比起前几年严峻了很多。根据牛客网、offershow小程序、脉脉、qq微信群等渠道收集汇总了一波2023届秋招技术岗薪资情况&#xff0c;发现对比2022届秋招薪资基本没有太大变化&#xff0c;往年秋招出现的倒挂现象在23届的秋招中消失了。一起来看下2023届秋招技术岗薪…

Hashtable底层原理分析

特点 1、存放k-v键值对 2、key\value均不能是null&#xff0c;否则会抛出空指针异常NullPointerException 3、线程安全的&#xff0c;底层使用synchronized 高频问题 1、初始化大小多少&#xff1f;什么时候初始化&#xff1f; 答&#xff1a;默认11&#xff0c;在第一次put…

流量主开通一周,收益55块了,周末可以加个鸡腿!记录一下我开通流量主到有收益的艰难过程!

文章目录公众号【字节卷动】账号历程注册写文冻结解冻漫无目的的写作重新出发大佬带我憧憬申请流量主失败腾讯客服有人工吗&#xff1f;白高兴一场流量主正式开通全力开干付出总有回报总结公众号【字节卷动】账号历程 注册 其实在2017年1月我就注册了公众号&#xff0c;但是一…

【网络原理5】IP协议篇

目录 IP协议报头 4位版本号 4位首部长度 8位服务类型(TOS) 16位总长度 IP拆包 16位标识、3位标志、13位片偏移​编辑 8位生存时间(TTL) 8位协议 16位首部校验和 网络地址管理 32位源ip&32位目的ip 方案一:动态分配ip地址 方案2:NAT网络地址转换(使用一个ip代…

docker中安装Mariadb

一、 docker中下载mariadb我的安装的版本是10.1.21&#xff0c;&#xff08;大家可以根据自己的需求制定版本&#xff09;docker pull mariadb:10.1.21 二、新建一个目录作为容器的映射目录新建目录用来将容器的目录及数据挂载到该目录下mkdir -p /data/mariadb/data 三、启动m…

Java反序列化漏洞——CommonsCollections1链分析

CC1的链在jdk-8u71之后因为AnnotationInvocationHandler的修改已无法利用。一、TransformedMap基于jdk-8u65进行试验1.Rutime.getRuntime().exec()Runtime.getRuntime().exec("calc");2.Runtime类不允许序列化&#xff0c;所有需要调用反射进行命令执行&#xff0c;将…

无需经验的steam搬砖,每天操作1小时,轻松创业赚钱!

我作为一个95后社畜&#xff0c;就喜欢倒腾各种赚钱的事情&#xff0c;8年老韭菜告诉你&#xff0c;副业创收一点都不难&#xff0c;难就难在是否找对项目&#xff0c;俗话说方向不对&#xff0c;努力白费&#xff01; 什么做苦力、技能、直播卖货&#xff0c;电商等等对比我这…

面试题59 - II. 队列的最大值

题目 请定义一个队列并实现函数 max_value 得到队列里的最大值&#xff0c;要求函数max_value、push_back 和 pop_front 的均摊时间复杂度都是O(1)。 若队列为空&#xff0c;pop_front 和 max_value 需要返回 -1 思路 对于一个普通队列&#xff0c;push_back 和 pop_front…

ChatGPT 简介

目录1 背景与发展历程1.1 背景1.2 发展历程2 技术原理2.1 第一阶段&#xff1a;训练监督策略模型2.2 第二阶段&#xff1a;训练奖励模型2.3 第三阶段&#xff1a;采用强化学习来增强模型的能力。3 国内使用情况及应用的领域4 面临的数据安全挑战与建议4.1 ChatGPT获取数据产生的…

传奇SF架设问题处理方式

传奇SF架设问题处理方式 正常开服当中我们会遇到很多问题&#xff0c;比如游戏黑屏、登录器链接失败等等。 接下来我会把经常会遇到的问题罗列出来以及解决方法附上 传奇M2引擎出现时间格式报错&#xff1f; 这个解决方法有两种第一种是在你电脑桌面的右下角修改时间格式为短…

开源堡垒机GateOne安装

GateOne 是一款基于 html5 实现的 ssh 客户端&#xff0c;有如下特点&#xff1a;不需要任何浏览器插件支持多用户和多终端&#xff0c;同时支持上百个用户和终端终端支持高级特性&#xff0c;例如 256 色彩&#xff0c;高级文本样式支持支持终端截图&#xff0c;保存为图片和 …

【Oracle实用小技巧一】

PLSQL里一些实用的小技巧&#xff0c;可以让日常工作更便捷。 1、PLSQL可以直接打开命令行测试语句&#xff0c;非常方便&#xff0c;可以在SQL窗口里测试好语句&#xff0c;再在SQL文件里编写查询脚本。 2、describe tablename查询数据表结构&#xff1b; 3、upper(text)字…

Yakit实战技巧:用MITM热加载任意修改流量

背景 用户在使用 Yakit MITM 功能的时候&#xff0c;经常会遇到一些特殊需求&#xff1a; 我的数据包需要携带一些特征变量才能访问&#xff0c;但是浏览器无法做到&#xff0c;我可以批量修改流量新增某一个 Header 吗&#xff1f; 我可以在代理层面在所有流量中新增一个参数…