您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > JAVA

Java中的反射

时间:2023-03-12 16:20:43  来源:今日头条  作者:时过境迁0114

类加载器

(1)类的加载

当我们的程序在运行后,第一次使用某个类的时候,会将此类的class文件读取到内存,并将此类

的所有信息存储到一个Class对象中。

 

说明:

a.图中的Class对象是指:JAVA.lang.Class类的对象,此类由Java类库提供,专门用于存储类的信息。

b.我们程序中可以通过:"类名.class",或者"对象.getClass()"方法获取这个Class对象

(2)类的加载时机

a.创建类的实例。

b.调用类的静态变量,或者为静态变量赋值。

c.调用类的静态方法。

d.使用反射方式来强制创建某个类或接口对应的java.lang.Class对象。

e.初始化某个类的子类。

f.直接使用java.exe命令来运行某个主类。

以上六种情况的任何一种,都可以导致JVM将一个类加载到方法区。

(3)类加载器

类加载器:是负责将磁盘上的某个class文件读取到内存并生成Class的对象。

Java中有三种类加载器,它们分别用于加载不同种类的class:

a.启动类加载器(Bootstrap ClassLoader):用于加载系统类库<JAVA_HOME>bin目录下的class,例如:rt.jar。

b.扩展类加载器(Extension ClassLoader):用于加载扩展类库<JAVA_HOME>libext目录下的class。

c.应用程序类加载器(Application ClassLoader):用于加载我们自定义类的加载器。

public class Test{ public static void mAIn(String[] args) {
    System.out.println(Test.class.getClassLoader());//sun.misc.Launcher$AppClassLoader
    System.out.println(String.class.getClassLoader());//null(API中说明:一些实现 可能使用null来表示引导类加载器。 如果此类由引导类加载器加载,则此方法将在此类实现中返回null。 )
    }
}

(4)双亲委派机制

 

上图展示了"类加载器"的层次关系,这种关系称为类加载器的"双亲委派模型":

a."双亲委派模型"中,除了顶层的启动类加载器外,其余的类加载器都应当有自己的"父级类加载器"。

b.这种关系不是通过"继承"实现的,通常是通过"组合"实现的。通过"组合"来表示父级类加载器。

c."双亲委派模型"的工作过程:

i. 某个"类加载器"收到类加载的请求,它首先不会尝试自己去加载这个类,而是把请求交给父

级类加载器。

ii.因此,所有的类加载的请求最终都会传送到顶层的"启动类加载器"中。

iii.如果"父级类加载器"无法加载这个类,然后子级类加载器再去加载。

(5)双亲委派机制的好处

双亲委派机制的一个显而易见的好处是:Java的类随着它的类加载器一起具备了一种带有优先级的层次

关系。例如:java.lang.Object。它存放在rt.jar中。无论哪一个类加载器要加载这个类,最终都是委派

给处于顶端的"启动类加载器"进行加载,因此java.lang.Object类在程序的各种类加载器环境中都是同一

个类。

相反,如果没有"双亲委派机制",如果用户自己编写了一个java.lang.Object,那么当我们编写其它类

时,这种隐式的继承使用的将会是用户自己编写的java.lang.Object类,那将变得一片混乱。

反射的概述

(1)反射的引入

问题:IDEA中的对象是怎么知道类有哪些属性,哪些方法的呢?

答:通过反射技术对象类进行了解剖得到了类的所有成员。

(2)反射的概念

反射是一种机制,利用该机制可以在程序运行过程中对类进行解剖并操作类中的所有成员(成员变量,成员方 法,构造方法)。

(3)使用反射操作类成员的前提

要获得该类字节码文件对象,就是Class对象。

(4)反射在实际开发中的应用

a.开发IDEA(集成开发环境),比如IDEA,Eclipse

b.各种框架设计和学习 比如Spring,Mybaits....

Class对象的获取方式

(1)三种获取方式

方式1: 通过类名.class获得

方式2:通过对象名.getClass()方法获得

方式3:通过Class类的静态方法获得: static Class forName("类全名")

每一个类的Class对象都只有一个。

示例代码:

package com.test.code.reflex;

public class Student {
}

public class Demo01 {
    public static void main(String[] args) throws ClassNotFoundException {
        // 获得Student类对应的Class对象
        Class<Student> c1 = Student.class;


        // 创建学生对象
        Student stu = new Student();
        Class<? extends Student> c2 = stu.getClass();
        System.out.println(c1 == c2);

        // 通过Class类的静态方法获得: static Class forName("类全名")
        Class<?> c3 = Class.forName("com.test.code.reflex.Student");
        System.out.println(c1 == c3);
        System.out.println(c2 == c3);

    }
}

Demo01运行结果:

 

(2)Class类常用方法

String getSimpleName(); 获得类名字符串:类名 
String getName(); 获得类全名:包名+类名 
T newInstance() ; 创建Class对象关联类的对象

示例代码:

public class Demo02 {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        // 获得Class对象
        Class<Student> c = Student.class;

        // 获得类名字符串:类名
        System.out.println(c.getSimpleName());

        // 获得类全名:包名 + 类名
        System.out.println(c.getName());

        // 创建对象
        Student stu = (Student)c.newInstance();
        System.out.println(stu);
    }
}

Demo02运行结果:

 

4.反射之操作构造方法

(1)Constructor类概述

反射之操作构造方法的目的:获得Constructor对象来创建类的对象。

Constructor类概述:类中的每一个构造方法都是一个Constructor类的对象

(2)Class类中与Constructor相关的方法

1. Constructor getConstructor(Class... parameterTypes)
* 根据参数类型获得对应的Constructor对象。
* 只能获得public修饰的构造方法
2. Constructor getDeclaredConstructor(Class... parameterTypes)
* 根据参数类型获得对应的Constructor对象
* 可以是public、protected、(默认)、private修饰符的构造方法。
3. Constructor[] getConstructors()
* 获得类中的所有构造方法对象,只能获得public的
4. Constructor[] getDeclaredConstructors()
* 获得类中的所有构造方法对象
* 可以是public、protected、(默认)、private修饰符的构造方法。

(3)Constructor对象常用方法

1. T newInstance(Object... initargs)"—— 根据指定的参数创建对象
2. void setAccessible(true) 设置"暴力反射"——是否取消权限检查,true取消权限检查,false表示不取消

示例代码:

public class Student {

    private String name;
    private String sex;
    private int age;

    //公有构造方法
    public Student(String name, String sex, int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

    //私有构造方法
    private Student(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }

}
public class Demo03 {

    /**
     * Constructor[] getConstructors()
     *      获得类中的所有构造方法对象,只能获得public的
     * Constructor[] getDeclaredConstructors()
     *      获得类中的所有构造方法,包括private修饰的
     */
    @Test
    public void test03(){
        // 获得Class对象
        Class<Student> c = Student.class;

        // 获得类中的所有构造方法对象,只能是public修饰的
        Constructor<?>[] cons_one = c.getConstructors();
        for (Constructor<?> con : cons_one) {
            System.out.println(con);
        }

        System.out.println("--------------------------------");

        // 获取类中所有的构造方法,包括public、protected、(默认)、private的
        Constructor<?>[] cons_two = c.getDeclaredConstructors();
        for (Constructor<?> con : cons_two) {
            System.out.println(con);
        }

    }

    /**
     * Constructor getDeclaredConstructor(Class... parameterTypes)
     *      根据参数类型获得对应的Constructor对象
     */
    @Test
    public void test02() throws Exception {
        // 获得Class对象
        Class<Student> c = Student.class;

        // 获得两个参数构造方法对象
        Constructor<Student> con = c.getDeclaredConstructor(String.class, String.class);
        // 取消权限检查(暴力反射)
        con.setAccessible(true);
        // 根据构造方法创建对象
        Student stu = con.newInstance("liuyifei", "女");
        System.out.println(stu);

    }

    /**
     * Constructor getConstructor(Class... parameterTypes)
     *      根据参数类型获得对应的Constructor对象
     */
    @Test
    public void test01() throws Exception {
        // 获得Class对象
        Class<Student> c = Student.class;

        // 获得无参数构造方法对象 注意:记得在Student类中加无参构造方法,不然会报错
        Constructor<Student> con = c.getConstructor();

        // 根据构造方法创建对象
        Student student = con.newInstance();
        System.out.println(student);

        // 获得有参数的构造方法对象
        Constructor<Student> con2 = c.getConstructor(String.class, String.class, int.class);
        // 创建对象
        Student stu2 = con2.newInstance("jack", "男", 18);
        System.out.println(stu2);
    }

}

5.反射之操作成员方法

(1)Method类概述

反射之操作成员方法的目的:操作Method对象来调用成员方法
Method类概述:每一个成员方法都是一个Method类的对象。

(2)Class类中与Method相关的方法

* Method getMethod(String name,Class...args);
根据方法名和参数类型获得对应的构造方法对象,只能获得public的
* Method getDeclaredMethod(String name,Class...args);
根据方法名和参数类型获得对应的构造方法对象,包括public、protected、(默认)、private的
* Method[] getMethods();
获得类中的所有成员方法对象,返回数组,只能获得public修饰的且包含父类的
* Method[] getDeclaredMethods();
获得类中的所有成员方法对象,返回数组,只获得本类的,包括public、protected、(默认)、 private的

(3)Method对象常用方法

* Object invoke(Object obj, Object... args)
调用指定对象obj的该方法
args:调用方法时传递的参数
* void setAccessible(true)
设置"暴力访问"——是否取消权限检查,true取消权限检查,false表示不取消

示例代码:

public class Demo04 {

    /**
     * Method[] getMethods();
     * 获得类中的所有成员方法对象,返回数组,只能获得public修饰的且包含父类的
     * Method[] getDeclaredMethods();
     * 获得类中的所有成员方法对象,返回数组,只获得本类的,包含private修饰的
     */
    @Test
    public void test03() {
        // 获得Class对象
        Class<Student> c = Student.class;

        // 获得类中的所有成员方法对象,返回数据,只能获得public修饰的且包含父类的
        // Method[] methods = c.getMethods();

        // 获得类中的所有成员方法对象,返回数组,只获得本类的,包含private修饰的
        Method[] methods = c.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
    }

    /**
     * Method getDeclaredMethod(String name,Class...args);
     * 根据方法名和参数类型获得对应的构造方法对象,
     */
    @Test
    public void test02() throws Exception {
        // 获得Class对象
        Class<Student> c = Student.class;

        // 根据Class对象创建学生对象
        Student stu = c.newInstance();
        // 获得sleep方法对应的Method对象
        Method m = c.getDeclaredMethod("sleep");
        // 暴力反射
        m.setAccessible(true);
        // 通过m对象执行sleep方法
        m.invoke(stu);
    }

    /**
     * Method getMethod(String name,Class...args);
     * 根据方法名和参数类型获得对应的构造方法对象,
     */
    @Test
    public void test01() throws Exception {
        // 获得Class对象
        Class<Student> c = Student.class;

        // 根据Class对象创建学生对象
        Student stu = c.newInstance();

//        // 获得study方法对应的Method对象
//        Method m = c.getMethod("study");
//        // 通过m对象执行study方法
//        m.invoke(stu);

        // 获得study方法对应的Method对象
        Method m2 = c.getMethod("study", int.class);
        // 通过m2对象执行study方法
        m2.invoke(stu, 8);
    }

}

6.反射之操作成员变量

(1)Field类概述

反射之操作成员变量的目的 :通过Field对象给对应的成员变量赋值和取值
Field类概述: 每一个成员变量都是一个Field类的对象。

(2)Class类中与Field相关的方法

Field getField(String name);
根据成员变量名获得对应Field对象,只能获得public修饰
Field getDeclaredField(String name);
根据成员变量名获得对应Field对象,包括public、protected、(默认)、private的
Field[] getFields();
获得所有的成员变量对应的Field对象,只能获得public的
Field[] getDeclaredFields();
获得所有的成员变量对应的Field对象,包括public、protected、(默认)、private的

(3)Field对象常用方法

void set(Object obj, Object value)
void setInt(Object obj, int i)
void setLong(Object obj, long l)
void setBoolean(Object obj, boolean z)
void setDouble(Object obj, double d)
Object get(Object obj)
int getInt(Object obj)
long getLong(Object obj)
boolean getBoolean(Object ob)
double getDouble(Object obj)
void setAccessible(true); // 暴力反射,设置为可以直接访问私有类型的属性。
Class getType(); // 获取属性的类型,返回Class对象。

setXxx方法都是给对象obj的属性设置使用,针对不同的类型选取不同的方法。

getXxx方法是获取对象obj对应的属性值的,针对不同的类型选取不同的方法。

示例代码:

public class Student {

    public String name;
    private String gender;

    public String toString() {
        return "Student [name = " + name + " , gender = " + gender + "]";
    }

}
public class Demo05 {

    /**
     * Field[] getFields();
     * 获得所有的成员变量对应的Field对象,只能获得public的
     * Field[] getDeclaredFields();
     * 获得所有的成员变量对应的Field对象,包含private的
     */
    @Test
    public void test02(){
        // 获得Class对象
        Class<Student> c = Student.class;

        // 获得所有的成员变量对应的Field对象
        // Field[] fields = c.getFields();

        // 获得所有的成员变量对应的Field对象,包括private
        Field[] fields = c.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }

    }

    /**
     * Field getField(String name);
     *      根据成员变量名获得对应Field对象,只能获得public修饰
     * Field getDeclaredField(String name);
     *      根据成员变量名获得对应Field对象,包含private修饰的
     */
    @Test
    public void test01() throws Exception {
        // 获得Class对象
        Class<Student> c = Student.class;

        // 创建对象
        Student stu = c.newInstance();

        // 获得成员变量name对应的Field对象
        Field f = c.getField("name");
        // 给成员变量name赋值
        // 给指定对象stu的name属性赋值为jack
        f.set(stu,"jack");

        // 获得指定对象stu成员变量name的值
        System.out.println(f.get(stu)); // jack
        //  获得成员变量的名字
        System.out.println(f.getName()); //name

        // 给成员变量gender赋值
        // 获得成员变量gender对应的Field对象
        Field f1 = c.getDeclaredField("gender");
        // 暴力反射
        f1.setAccessible(true);
        // 给指定对象stu的gender属性赋值为男
        f1.set(stu,"男");

        System.out.println(stu);
    }

}

wx搜索“自律的西瓜L”



Tags:Java   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
17 个你需要知道的 JavaScript 优化技巧
你可能一直在使用JavaScript搞开发,但很多时候你可能对它提供的最新功能并不感冒,尽管这些功能在无需编写额外代码的情况下就可以解决你的问题。作为前端开发人员,我们必须了解...【详细内容】
2024-04-03  Search: Java  点击:(5)  评论:(0)  加入收藏
你不可不知的 15 个 JavaScript 小贴士
在掌握如何编写JavaScript代码之后,那么就进阶到实践&mdash;&mdash;如何真正地解决问题。我们需要更改JS代码使其更简单、更易于阅读,因为这样的程序更易于团队成员之间紧密协...【详细内容】
2024-03-21  Search: Java  点击:(27)  评论:(0)  加入收藏
Oracle正式发布Java 22
Oracle 正式发布 Java 22,这是备受欢迎的编程语言和开发平台推出的全新版本。Java 22 (Oracle JDK 22) 在性能、稳定性和安全性方面进行了数千种改进,包括对Java 语言、其API...【详细内容】
2024-03-21  Search: Java  点击:(10)  评论:(0)  加入收藏
构建一个通用灵活的JavaScript插件系统?看完你也会!
在软件开发中,插件系统为应用程序提供了巨大的灵活性和可扩展性。它们允许开发者在不修改核心代码的情况下扩展和定制应用程序的功能。本文将详细介绍如何构建一个灵活的Java...【详细内容】
2024-03-20  Search: Java  点击:(20)  评论:(0)  加入收藏
Java 8 内存管理原理解析及内存故障排查实践
本文介绍Java8虚拟机的内存区域划分、内存垃圾回收工作原理解析、虚拟机内存分配配置,以及各垃圾收集器优缺点及场景应用、实践内存故障场景排查诊断,方便读者面临内存故障时...【详细内容】
2024-03-20  Search: Java  点击:(14)  评论:(0)  加入收藏
如何编写高性能的Java代码
作者 | 波哥审校 | 重楼在当今软件开发领域,编写高性能的Java代码是至关重要的。Java作为一种流行的编程语言,拥有强大的生态系统和丰富的工具链,但是要写出性能优异的Java代码...【详细内容】
2024-03-20  Search: Java  点击:(24)  评论:(0)  加入收藏
在Java应用程序中释放峰值性能:配置文件引导优化(PGO)概述
译者 | 李睿审校 | 重楼在Java开发领域,优化应用程序的性能是开发人员的持续追求。配置文件引导优化(Profile-Guided Optimization,PGO)是一种功能强大的技术,能够显著地提高Ja...【详细内容】
2024-03-18  Search: Java  点击:(25)  评论:(0)  加入收藏
对JavaScript代码压缩有什么好处?
对JavaScript代码进行压缩主要带来以下好处: 减小文件大小:通过移除代码中的空白符、换行符、注释,以及缩短变量名等方式,可以显著减小JavaScript文件的大小。这有助于减少网页...【详细内容】
2024-03-13  Search: Java  点击:(2)  评论:(0)  加入收藏
跨端轻量JavaScript引擎的实现与探索
一、JavaScript 1.JavaScript语言JavaScript是ECMAScript的实现,由ECMA 39(欧洲计算机制造商协会39号技术委员会)负责制定ECMAScript标准。ECMAScript发展史: 2.JavaScript...【详细内容】
2024-03-12  Search: Java  点击:(2)  评论:(0)  加入收藏
面向AI工程的五大JavaScript工具
令许多人惊讶的是,一向在Web开发领域中大放异彩的JavaScript在开发使用大语言模型(LLM)的应用程序方面同样大有价值。我们在本文中将介绍面向AI工程的五大工具,并为希望将LLM...【详细内容】
2024-02-06  Search: Java  点击:(53)  评论:(0)  加入收藏
▌简易百科推荐
Java 8 内存管理原理解析及内存故障排查实践
本文介绍Java8虚拟机的内存区域划分、内存垃圾回收工作原理解析、虚拟机内存分配配置,以及各垃圾收集器优缺点及场景应用、实践内存故障场景排查诊断,方便读者面临内存故障时...【详细内容】
2024-03-20  vivo互联网技术    Tags:Java 8   点击:(14)  评论:(0)  加入收藏
如何编写高性能的Java代码
作者 | 波哥审校 | 重楼在当今软件开发领域,编写高性能的Java代码是至关重要的。Java作为一种流行的编程语言,拥有强大的生态系统和丰富的工具链,但是要写出性能优异的Java代码...【详细内容】
2024-03-20    51CTO  Tags:Java代码   点击:(24)  评论:(0)  加入收藏
在Java应用程序中释放峰值性能:配置文件引导优化(PGO)概述
译者 | 李睿审校 | 重楼在Java开发领域,优化应用程序的性能是开发人员的持续追求。配置文件引导优化(Profile-Guided Optimization,PGO)是一种功能强大的技术,能够显著地提高Ja...【详细内容】
2024-03-18    51CTO  Tags:Java   点击:(25)  评论:(0)  加入收藏
Java生产环境下性能监控与调优详解
堆是 JVM 内存中最大的一块内存空间,该内存被所有线程共享,几乎所有对象和数组都被分配到了堆内存中。堆被划分为新生代和老年代,新生代又被进一步划分为 Eden 和 Survivor 区,...【详细内容】
2024-02-04  大雷家吃饭    Tags:Java   点击:(57)  评论:(0)  加入收藏
在项目中如何避免和解决Java内存泄漏问题
在Java中,内存泄漏通常指的是程序中存在一些不再使用的对象或数据结构仍然保持对内存的引用,从而导致这些对象无法被垃圾回收器回收,最终导致内存占用不断增加,进而影响程序的性...【详细内容】
2024-02-01  编程技术汇  今日头条  Tags:Java   点击:(68)  评论:(0)  加入收藏
Java中的缓存技术及其使用场景
Java中的缓存技术是一种优化手段,用于提高应用程序的性能和响应速度。缓存技术通过将计算结果或者经常访问的数据存储在快速访问的存储介质中,以便下次需要时可以更快地获取。...【详细内容】
2024-01-30  编程技术汇    Tags:Java   点击:(72)  评论:(0)  加入收藏
JDK17 与 JDK11 特性差异浅谈
从 JDK11 到 JDK17 ,Java 的发展经历了一系列重要的里程碑。其中最重要的是 JDK17 的发布,这是一个长期支持(LTS)版本,它将获得长期的更新和支持,有助于保持程序的稳定性和可靠性...【详细内容】
2024-01-26  政采云技术  51CTO  Tags:JDK17   点击:(89)  评论:(0)  加入收藏
Java并发编程高阶技术
随着计算机硬件的发展,多核处理器的普及和内存容量的增加,利用多线程实现异步并发成为提升程序性能的重要途径。在Java中,多线程的使用能够更好地发挥硬件资源,提高程序的响应...【详细内容】
2024-01-19  大雷家吃饭    Tags:Java   点击:(106)  评论:(0)  加入收藏
这篇文章彻底让你了解Java与RPA
前段时间更新系统的时候,发现多了一个名为Power Automate的应用,打开了解后发现是一个自动化应用,根据其描述,可以自动执行所有日常任务,说的还是比较夸张,简单用了下,对于office、...【详细内容】
2024-01-17  Java技术指北  微信公众号  Tags:Java   点击:(98)  评论:(0)  加入收藏
Java 在 2023 年仍然流行的 25 个原因
译者 | 刘汪洋审校 | 重楼学习 Java 的过程中,我意识到在 90 年代末 OOP 正值鼎盛时期,Java 作为能够真正实现这些概念的语言显得尤为突出(尽管我此前学过 C++,但相比 Java 影响...【详细内容】
2024-01-10  刘汪洋  51CTO  Tags:Java   点击:(75)  评论:(0)  加入收藏
站内最新
站内热门
站内头条