反射Reflect(Java基础篇)

2024-05-02 01:38
文章标签 java 基础 反射 reflect

本文主要是介绍反射Reflect(Java基础篇),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

	1>.Java反射机制概述2>.理解Class类并获取Class实例3>.类的加载与ClassLoader的理解4>.创建运行时类的对象5>.获取运行时类的Constructor5>.获取运行时类的Field6>.获取运行时类的Method7>.反射的应用:动态代理

①. Java反射概述

1>.Java反射概述

  • ①. Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法

  • ②. 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息

我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射
在这里插入图片描述

在这里插入图片描述在这里插入图片描述

②. 获取Class的四种方法

2>. Class类

1.Class类的概述

  • 程序在经过javac.exe 命令以后,会生成一个或多个字节码文件(.class结尾),接着我们用java.exe 命令对某个字节码文件进行解释运行。将某个字节码文件加载到内存中。此过程称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例

2. 四种获取Class类实例[ 掌握 ]

  • ①. 调用运行时类的属性:Class<Person>clazz1=Person.class;

  • ②. 通过运行时类的对象,调用getClass()

该方法是Object类中的方法,所有的Java对象都可以调用该方法

  • ③. 调用Class的静态方法: forName(String classPath)

  • ④. 使用类的加载器: ClassLoader[了解 ]

    @Testpublic void fun1()throws Exception{//方式一:调用运行时类的属性//Class<Person>clazz1=Person.class;Class<Person>clazz1=Person.class;System.out.println(clazz1);//class itheima.com.Person//方式二:通过运行时类的对象,调用getClass()Person p1=new Person();Class clazz2 = p1.getClass();System.out.println(clazz2);//方式三: 调用Class的静态方法: forName(String classPath)Class clazz3=Class.forName("itheima.com.Person");System.out.println(clazz3);//方式四:使用类的加载器: ClassLoader[了解 ]//ClassLoader classLoader2=new ReflectionDemo1().getClass().getClassLoader();ClassLoader classLoader=ReflectionDemo1.class.getClassLoader();Class clazz4=classLoader.loadClass("itheima.com.Person");System.out.println(clazz4);}

哪些Class类并获取Class实例
1.class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
2.interface:接口
3.[ ]:数组
4.enum:枚举
5.annotation:注解@interface
6.primitive type:基本数据类型
7.void

在这里插入图片描述

③. ClassLoader

3>. 类加载器的介绍

  • ①. JVM支持两种类型的类加载器,分别为引导类加载器(Bootstrap ClassLoader)和自定义类加载器(User-Defined ClassLoader)

  • ②. 从概念上来讲,自定义类加载器一般指的是程序中由开发人员自定义的一类类加载器,但是Java虚拟机规范并没有这么定义,而是将所有派生于抽象类ClassLoader的类加载器都划分为自定义类加载器

  • ③. sum.misc.Launcher:它是一个java虚拟机的入口应用

  • ④. 无论类加载器的类型如何划分,在程序中我们常见的类加载器始终只有3个,如下所示:

在这里插入图片描述
在这里插入图片描述

    @Testpublic void fun2(){//对于自定义类,使用系统类加载器进行加载ClassLoader classLoader = ReflectionDemo1.class.getClassLoader();System.out.println(classLoader);//jdk.internal.loader.ClassLoaders$AppClassLoader@726f3b58//调用系统类加载器getParent():获取扩展类加载器ClassLoader classLoader1 = classLoader.getParent();System.out.println(classLoader1);//$PlatformClassLoader@e73f9ac//调用扩展类加载器的getParent():无法获取引导类加载器//引导类加载器主要负责java的核心类库,无法加载自定义类ClassLoader classLoader2 = classLoader1.getParent();System.out.println(classLoader2);//null}
@Test(使用ClassLoader加载配置文件)public void fun3()throws Exception{//此时的文件默认在当前的moudule下
/*        Properties prop=new Properties();FileInputStream fis=new FileInputStream("a.properties");*/
//      读取配置文件的方式二: 使用classLoader//配置文件默认识别为:当前mouble的src下ClassLoader classLoader=ReflectionDemo1.class.getClassLoader();InputStream is=classLoader.getResourceAsStream("a.properties");Properties prop=new Properties();prop.load(is);String username=prop.getProperty("username");System.out.println(username);}

在这里插入图片描述

①. 启动类加载器

1.启动类加载器(引导类加载器 Bootstrap ClassLoader)

  • ①. 这个类加载使用C/C++语言实现的,嵌套在JVM内部

  • ②. 它用来加载Java的核心类库(JAVA_HOME/jre/lib/rt.jar、resource.jar或sum.boot.class.path路径下的内容),用于提供JVM自身需要的类

  • ③. 并不继承自java.lang.ClassLoader,没有父加载器

  • ④. 加载扩展类和应用程序类加载器,并指定为他们的父类加载器

  • ⑤. 由于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类

②. 扩展类加载器(Extension ClassLoader)

2.扩展类加载器

  • ①. Java语言编写,由sum.music.Launcher$ExtClassLoader实现

  • ②. 派生于ClassLoader类

  • ③.父类加载器为启动类加载器

  • ④.从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的jre/lib/ext子目录(扩展目录)下加载类库。如果用户创建的JAR放在此目录下,也贵自动由扩展类加载器加载

③. 应用程序类加载器(系统类加载器)

3.应用程序类加载器(系统类加载器 AppClassLoader)

  • ①. java语言编写,由sum.misc.Launcher$AppClassLoader实现

  • ②. 派生于ClassLoader类

  • ③. 父类加载器为扩展类加载器

  • ④. 它负责加载环境变量classpath或系统属性java.class.path指定路径下的类库

  • ⑤.该类加载是程序中默认的类加载器,一般来说,Java应用的类都是由它来完成加载

  • ⑥. 通过ClassLoader#getSystemClassLoader()方法可以获取到该类加载器

④. 用户自定义类加载器(了解)

4.用户自定义类加载器

  • 在Java的日常应用程序开发中,类的加载几乎是由上述3种类加载器相互配合执行的,在必要时,我们换可以自定义类加载器,来定制类的加载方式

  • 如果获取ClassLoader

在这里插入图片描述

⑤. 双亲委派机制 掌握

5. 双亲委派机制(掌握)

  • ①. 工作原理

在这里插入图片描述

  • ②. 优势:
    在这里插入图片描述

⑥. 沙箱安全机制

6. 沙箱安全机制(掌握)

在这里插入图片描述

⑦. 如何判断两个Class对象是否相同

7.如何判断两个Class对象是否相同

  • ①. 相同必须的两个条件如下:

在这里插入图片描述

  • ②. JVM必须知道一个类型是由启动加载器加载还是用户类加载器加载的。如果一个类型是又用户类加载器加载的,那么JVM会将这个类加载器的一个引用作为类型信息的一部分保存在方法区中。

⑧. 主动使用和被动使用

8.主动使用和被动使用

在这里插入图片描述

④. 创建运行时类的对象

4>. 创建运行时类的对象

1. 创建运行时类对象

  • newInstance( ):调用此方法创建对应运行时类的对象;内部调用了运行时类的空参构造方法要想此方法正常的创建运行时类的对象,要求:

  • ①. 运行时类必须提供空参的构造器

  • ②. 空参的构造器的访问权限得够。通常,设置为public

2. 要求

  • 在javaBean中要求提供一个public的空参构造器。原因:

  • ①. 便于通过反射,创建运行时类的对象

  • ②. 便于子类继承此运行时类时,默认调用super()时,保证父类有此构造器

        Class clazz=Person.class;
/*      Object obj = clazz.newInstance();Person p=(Person)obj;*/Person p=(Person) clazz.newInstance();System.out.println(p);

5>. 反射获取构造方法并使用

  • ①. Constructor<?>[ ] getConstructors():返回所有公共构造方法对象的数组

  • ②. Constructor<?> [ ] getDeclaredConstructors():返回所有构造方法对象的数组

  • ③. Constructor<T> getConstructor​(Class<?>... parameterTypes) :返回单个公共构造方法对象

参数:你要获取的构造方法的参数的个数和数据类型对应的字节码文件对象 .class

  • ④. Constructor<T> getDeclaredConstructor​(Class<?>... parameterTypes) :返回单个构造方法对象

Constructor 类中用于创建对象的方法

  • T newInstance(Object ...initargs):根据指定的构造方法创建对象

  • public void setAccessible​(boolean flag):值为true,取消访问检查

在这里插入图片描述
在这里插入图片描述

/*通过反射实现如下的操作:Student s = new Student("林青霞",30,"西安");System.out.println(s);*/
public class ReflectDemo02 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {//获取Class对象Class<?> c = Class.forName("com.itheima_02.Student");//public Student(String name, int age, String address)//Constructor<T> getConstructor​(Class<?>... parameterTypes)Constructor<?> con = c.getConstructor(String.class, int.class, String.class);//基本数据类型也可以通过.class得到对应的Class类型//T newInstance​(Object... initargs)Object obj = con.newInstance("林青霞", 30, "西安");System.out.println(obj);}
}

在这里插入图片描述

⑤. 反射获取成员变量并使用

5>. 反射获取成员变量并使用

  • ①. Field[ ] getFields():返回所有公共成员变量对象的数组

  • ②. Field[ ]getDeclaredFields():`返回所有成员变量对象的数组

  • ③. Field[ ] getField(String name):返回单个公共成员变量对象

  • ④. Field getDeclaredFiled(String name):返回单个成员变量对象

Field 类中用于给成员变量赋值的方法

  • ⑤. void set(Object obj,Object value):给obj对象的成员变量赋值为value
    @Testpublic  void fun6()throws Exception{Class clazz=Class.forName("itheima.com.Person");//Person p = (Person) clazz.newInstance();//公共的成员变量Field[] fields = clazz.getFields();for(Field field:fields){System.out.println(field);//public int itheima.com.Person.age}//所有的成员变量Field[] declaredFields = clazz.getDeclaredFields();for(Field field2:declaredFields){System.out.println(field2);//private java.lang.String itheima.com.Person.name//public int itheima.com.Person.age}System.out.println("-------");//获取一个成员变量Field ageField = clazz.getField("age");System.out.println(ageField);//public int itheima.com.Person.age//创建对象Constructor con = clazz.getConstructor();Object p = con.newInstance();//void set(Object obj,Object value):将指定对象参数中由此Field对象表示的字段设置为指定的新值ageField.set(p,11);System.out.println(p);//Person{name='null', age=11}}

在这里插入图片描述

⑥. 反射获取成员方法并使用

6>. 反射获取成员方法并使用

Class类中用于获取成员方法的方法

  • ①. Method [ ] getMethods():返回所有公共成员方法对象的数组,包括继承的

  • ②. Method[ ] getDeclaredMethods():返回所有成员变量对象的数组,不包括继承的

  • ③. Method getMethod(String name,Class<?> .....parameterTypes):返回单个公共成员方法对象

  • ④. Method getDeclaredMethod(String name,Class<?> .....parameterTypes):返回单个成员方法对象

Method类中用于调用成员方法的方法

  • Object invoke(Object obj,Object....args):调用obj对象的成员方法,参数是args,返回值是Object类型
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("method");}public void method2(String s) {System.out.println("method:" + s);}public String method3(String s, int i) {return s + "," + i;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", address='" + address + '\'' +'}';}
}
/*练习:通过反射实现如下操作Student s = new Student();s.method1();s.method2("林青霞");String ss = s.method3("林青霞",30);System.out.println(ss);s.function();*/
public class ReflectDemo02 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {//获取Class对象Class<?> c = Class.forName("com.itheima_02.Student");//Student s = new Student();Constructor<?> con = c.getConstructor();Object obj = con.newInstance();//s.method1();Method m1 = c.getMethod("method1");m1.invoke(obj);//s.method2("林青霞");Method m2 = c.getMethod("method2", String.class);m2.invoke(obj,"林青霞");//        String ss = s.method3("林青霞",30);
//        System.out.println(ss);Method m3 = c.getMethod("method3", String.class, int.class);Object o = m3.invoke(obj, "林青霞", 30);System.out.println(o);//s.function();
//        Method m4 = c.getMethod("function"); //NoSuchMethodException: com.itheima_02.Student.function()Method m4 = c.getDeclaredMethod("function");m4.setAccessible(true);m4.invoke(obj);}
}

⑦. 关于反射的练习

7>. 关于反射的练习

  • ①. 有一个ArrayList<Integer>集合,现在我想在这个集合中添加一个字符串数据,如何实现?
public class ReflectTest01 {public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {//创建集合ArrayList<Integer> array = new ArrayList<Integer>();//        array.add(10);
//        array.add(20);
//        array.add("hello");Class<? extends ArrayList> aClass = array.getClass();Method m1=aClass.getMethod("add",Object.class);m1.invoke(array,"hello");m1.invoke(array,"world");System.out.println(array);}
}
  • ②. 通过配置文件运行类中的方法
public class ReflectTest02 {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {//把文件中的数据通过Io流读取,读取后放入集合中Properties prop = new Properties();//FileReader fr = new FileReader("myReflect\\class.txt");FileReader fr = new FileReader("myReflect\\class.properties");prop.load(fr);fr.close();//获取到类名和方法名String className = prop.getProperty("className");String methodName = prop.getProperty("methodName");//通过反射来使用Class<?> c = Class.forName(className);//com.itheima_06.StudentConstructor<?> con = c.getConstructor();Object obj = con.newInstance();Method m = c.getMethod(methodName);//studym.invoke(obj);}
}

这篇关于反射Reflect(Java基础篇)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/953139

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

从基础到高级详解Go语言中错误处理的实践指南

《从基础到高级详解Go语言中错误处理的实践指南》Go语言采用了一种独特而明确的错误处理哲学,与其他主流编程语言形成鲜明对比,本文将为大家详细介绍Go语言中错误处理详细方法,希望对大家有所帮助... 目录1 Go 错误处理哲学与核心机制1.1 错误接口设计1.2 错误与异常的区别2 错误创建与检查2.1 基础

Java中的.close()举例详解

《Java中的.close()举例详解》.close()方法只适用于通过window.open()打开的弹出窗口,对于浏览器的主窗口,如果没有得到用户允许是不能关闭的,:本文主要介绍Java中的.... 目录当你遇到以下三种情况时,一定要记得使用 .close():用法作用举例如何判断代码中的 input