首页 > 编程语言 >Java-反射

Java-反射

时间:2024-09-02 23:37:17浏览次数:10  
标签:反射 Java System 获取 println 加载 Class out

1.类加载过程

类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载等七个阶段。

类加载器

加载就是将类的class文件读入内存后,创建一个Class对象,这个过程由类加载器完成,类加载器分为三类:

  • 启动类加载器
    该加载器负责加载存放在JDK\jre\lib类库,启动加载器是无法被Java程序直接引用,由JVM 调用;
  • 扩展类加载器
    该类加载器负责加载JDK\jre\lib\ext目录中,或者由Java.ext.dirs系统指定的路径中的所有类库(如Javax.*开头的类),开发者可以直接使用扩展类加载器;
  • 应用类加载器(程序员)
    加载用户类路径(ClassPath)所指定的类,开发者可以直接使用该类加载器(如果程序中没有自定义类加载器,一般情况下这个就是程序中默认的类加载器

初始化

JVM负责对类进行初始化,也就是对静态属性进行初始化。在Java中,对静态属性初始化的方式有两种:

  • 声明静态属性时指定初始值;
  • 使用静态初始化代码块为静态属性指定初始值。
    类加载过程主要是将Class文件加载到虚拟机内存中,真正执行字节码的操作是在类加载完成后才开始的。

反射

Java反射机制的核心是在程序运行时动态的加载类并获取类的详细信息,从而操作类或对象的属性和方法(本质是JVM得到Class对象后,再通过Class对象经行反编译,从而获取对象的各种信息)
程序运行时,动态的创建对象的方式称为反射
Java属于先编译在运行的语言,对象类型在编译期确定;
当程序在运行时可能需要动态加载某些类,通过反射可以在运行时动态的创建对象并调用其属性,不需要提前在编译期确定对象类型

反射的原理——类加载

传统静态加载类

Person person = new Person();
//编译时已确定对象的属性,程序运行时通过类加载器加载Person类,并创建该类的Class对象

反射动态加载类

Class object = Class.forName("Person");//引号里的是类全名
//编译时未确定对象类型,程序运行时通过类加载器无法加载Person类,只有程序执行到以上代码时,类加载器才知道对象类型,这时才开始加载Person类,创建该类的Class对象,并返回给object变量

Class对象

每一个类通过类加载器完成加载后,都会创建唯一的Class对象,用于保存类的元信息(属性、方法以及构造器)
Class对象属于Class类型,是类加载器创建的特殊对象,不是类的实例化对象

Class object = Class.forName("Person");
Person person =(Person)object.newInstance();

反射通过获得Class对象就可以得到类的元信息,调用newInstance()方法就是通过元信息来创建Person对象实例

三种获取Class对象的方式

  • ① 对象名.getclass----------------运行阶段
    通过类对象实例的getClass()方法——
    Person preson = new Person();
    Class object = person.getClass();
    
  • ② 类名.class---------------------加载阶段
    通过任何数据类型(包括基本数据类型)的静态class属性
    Class object = Person.class;
    
  • ③ Class.forName ("类全名")---------------------源代码阶段
    通过Class类的静态方法:forName(String className)
    Class object = Class.forName("Person");
    

注:第一种没必要,第二种需要导入类包依赖太强,第三种简单灵活

具体实现

package reflection;
/**
 * @author yeye
 * @desc
 * @date 2024/8/29 20:11
 */
public class Reflection01 {
    public static void main(String[] args) throws ClassNotFoundException {
        /**
         * 获取Class对象的三种方式
         * 1. 通过Class.forName("全类名")方法
         * 2. 通过类名.class属性
         * 3. 通过对象.getClass()方法
         */

        //第一种方式
        //全类名“包名.类名”
        //最常用
        Class clazz = Class.forName("reflection.Reflection01");
        System.out.println("第一种方式:" + clazz.getName());
        
        //第二种方式
        //一般更多的是当作参数传递给方法,所以用类名.class属性
        Class clazz2 = Reflection01.class;
        System.out.println("第二种方式:"+clazz2.getName());

        //第三种方式
        //一般用在对象实例化之后,获取对象的Class对象
        Reflection01 obj = new Reflection01();
        Class clazz3 = obj.getClass();
        System.out.println("第三种方式:"+clazz3.getName());
    }
}

两种方式创建对象实例

  • 使用Class对象的newInstance()方法
    Class object = Class.forName("Person");
    Person person = (Person)class.newInstance;
    
  • 使用Class对象获取Constructor对象,再调用newInstance()方法;
    Class object = Class.forName("person");
    Counstructor constructer = object.getConstructor(Person.class);
    Person person =(Person)constructor.newInstance("张三",18);
    

第一张构造器只能调用无参构造器,第二种可以调用有参构造器

反射的基本使用

  1. 使用Class对象获取Field对象
    具体如下代码:

    Class object = Class.forName("Person");
    Field fields[] = object.getDeclearedFields();
    
    package reflection;
    
    import java.lang.reflect.Field;
    
    /**
     * @author yeye
     * @desc  通过反射获取成员变量
     * @date 2024/9/1 23:01
     */
    public class Reflection03 {
        public static void main(String[] args) throws Exception {
            //1.获取class字节码文件对象
            Class clazz = Class.forName("reflection.Student");
            //2.获取成员变量
            //获取所有的公共的成员变量
            Field[] f1 = clazz.getFields();
            for(Field f:f1){
                System.out.println(f);
            }
            System.out.println("-------------");
            //获取所有的成员变量,包括私有的和受保护的
            Field[] f2 = clazz.getDeclaredFields();
            for(Field f:f2) {
                System.out.println(f);
            }
            System.out.println("-----------------------");
            //获取单个成员变量
            //获取gender(共有的)成员变量
            Field fie1 = clazz.getField("gender");
            System.out.println(fie1);
            //获取name(私有的)成员变量
            Field fie2 = clazz.getDeclaredField("name");
            System.out.println(fie2);
    
            //获取成员变量的名字
            String n = fie1.getName();
            System.out.println(n);
            //获取成员变量的类型
            Class type = fie2.getType();
            System.out.println(type);
        }
    }
    
  2. 使用Class对象获取Method方法
    具体如下代码

package reflection;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

/**
 * @author yeye
 * @desc 利用反射获取成员方法
 * @date 2024/9/2 16:31
 */
public class Reflection04 {
    public static void main(String[] args) throws Exception {
        //获取class字节码文件对象
        Class clazz = Class.forName("reflection.Student");

        //获取所有的公共方法(包含父类中所有的公共方法)
        Method []method1 = clazz.getMethods();
        for(Method method:method1){
            System.out.println(method);
        }
        //获取所有的方法
        Method[] method2 = clazz.getDeclaredMethods();
        for(Method method:method2){
            System.out.println(method);
        }
        //获取指定的单一方法
        Method method3 = clazz.getDeclaredMethod("study",String.class);
        System.out.println(method3);
        //获取方法的名字
        String name = method3.getName();
        System.out.println(name);
        //获取方法的修饰符
        int modifiers = method3.getModifiers();
        System.out.println(modifiers);
        //获取方法的形参
        Parameter[] parameters = method3.getParameters();
        for(Parameter parameter:parameters){
            System.out.println(parameter);
        }
        //获取方法的异常
        Class[] exceptionTypes = method3.getExceptionTypes();
        for(Class exceptionType:exceptionTypes){
            System.out.println(exceptionType);
        }
        //获取方法并运行
        Student m = new Student();
        method3.setAccessible(true);
        //参数一:m,表示方法的调用者
        //参数二:"汉堡包",表示在调用方法的时候传递的实际参数
        String result = (String) method3.invoke(m, "数学");
        System.out.println(result);
    }

Field 对象数组保存类的所有属性,Method对象数组保存类的所有方法
3. 获取构造方法
具体如下代码:

package reflection;

import java.lang.reflect.Constructor;
import java.sql.Connection;

/**
 * @author yeye
 * @desc     通过反射获取类的构造方法
 * @date 2024/9/1 21:32
 */
public class Reflection02 {
    public static void main(String[] args) throws Exception {

        //1、获取class字节码文件对象
        Class clazz = Class.forName("reflection.Student");

        //2、获取构造方法
        //第一种方法,获取所有的公共的构造方法
        Constructor[] cons1 = clazz.getConstructors();
        for (Constructor con : cons1) {
            System.out.println(con);
        }
        System.out.println("-------");
        //第二种方法,获取所有的构造方法,包括私有的
        Constructor[] cons2 = clazz.getDeclaredConstructors();
        for (Constructor con : cons2) {
            System.out.println(con);
        }
        System.out.println("-------");
        //3、获取单个的空参构造方法
        Constructor con1 = clazz.getDeclaredConstructor();
        System.out.println(con1);
        //4、获取单个的带参数的构造方法(String类型)
        Constructor con2 = clazz.getDeclaredConstructor(String.class);
        System.out.println(con2);
        //5.获取多个参数的构造方法
        Constructor con3 = clazz.getDeclaredConstructor(String.class, int.class);
        System.out.println(con3);

        //6.创建对象
        //第一种方法,调用空参构造方法
        Student stu1 = (Student) con1.newInstance();
        System.out.println(stu1);
        //第二种方法,调用带参构造方法
        //暴力反射,表示临时取消权限校验
        con3.setAccessible(true);
        Student stu2 = (Student) con3.newInstance("椰椰", 20);
        System.out.println(stu2);
    }
}

标签:反射,Java,System,获取,println,加载,Class,out
From: https://www.cnblogs.com/wmshun/p/18393741

相关文章

  • 【Java】Spring-AOP与拦截器实战 (上手图解)
    Java系列文章目录补充内容Windows通过SSH连接Linux第一章Linux基本命令的学习与Linux历史文章目录Java系列文章目录一、前言二、学习内容:三、问题描述四、解决方案:4.1认识依赖4.2使用AOP与拦截器4.2.1使用AOP4.2.1.1设置DemoAop类4.2.2.2设置切面4.2.2.3设......
  • [java][代码]Java中创建多线程方法
     在Java中,创建多线程有多种方法。以下是一些常见的方法:1.继承Thread类通过继承Thread类并重写其run方法来创建线程。classMyThreadextendsThread{publicvoidrun(){//线程要执行的任务System.out.println("线程运行中...");}......
  • java-基于spring boot在线装修管理系统
    摘要互联网发展至今,无论是其理论还是技术都已经成熟,而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播,搭配信息管理工具可以很好地为人们提供服务。针对信息管理混乱,出错率高,信息安全性差,劳动强度大,费时费力等问题,采用在线装修管理系统可以有效管理,使信息管理能......
  • [java][代码]在Java中将文本写入文件
    在Java中,有多种方法可以将文本写入文件。以下是一些常见的方法:1.使用FileWriter类FileWriter是最基本的字符输出流,可以用来写入字符文件。importjava.io.FileWriter;importjava.io.IOException;publicclassWriteFileExample{publicstaticvoidmain(Stri......
  • 时区以及时区对于Java时间类格式化的影响
    时区基本概念时区(TimeZone)是指地球上的一个地区与格林尼治标准时间(GMT)或协调世界时(UTC)之间的时间差异。由于地球自转的原因,不同的地理位置会有不同的时间。时区的划分使得世界各地能够更合理地安排时间,保持同步。UTC(协调世界时):UTC是一种标准时间,它没有受到地球自转速度变化......
  • Java LeetCode练习
        LeetCodeExercise        807.保持城市天际线    题解:贪心        从左侧和右侧看,城市天际线等于矩阵grid的每一行的建筑物高度最大值;从顶部和底部看,城市天际线等于矩阵grid的每一列的建筑物高度最大值。只要不改变每一行和每一列......
  • 「Java跳槽面试必备」2024年09月最新八股文
    【前言】网上各种面试八股文太多太多,但我今年找了好几个都是很久很久以前的老面试题,老文档了,和我出去面试市场上面试官问的问题基本上不一样了,可以说被打了一个措手不及,浪费了好几个机会,回来又找了好一些资料,以及结合自己最近的面试情况总结了一些心得免费分享给大家!虽然只有几本......
  • Java学习案例:控制台实现电影院管理系统
    文章目录@[TOC](文章目录)前言一、实现效果1、登录界面以及注册功能演示2、普通用户登录(1)热映影片(2)即将上映(3)个人信息(4)票夹3、管理员登录(1)电影管理(2)用户管理(3)个人信息二、功能源码1、接收用户的合法输入2、控制台格式化输出3、创建工具类4、多个类之间数据传递三......
  • 《JavaEE进阶》----9.<SpringMVC实践项目:【简易对话留言板(数据存在数据库中)】>
    本篇博客讲解设计的一个网页版简易对话留言板。这个是将数据存在数据库中。我们通过链接本地数据库。在这里面存入的数据。此时数据存在在硬盘中,只要数据不被删除,硬盘不损坏。那么这些数据就会被永久保存引入的依赖:配置数据库:spring:datasource:#数据库连接配置......
  • Java表达式与语句
    文章目录Java表达式和语句1.变量2.运算符与表达式3.语句Java表达式和语句1.变量变量及作用域局部变量在一个方法或由一对{}表示的代码块内定义的变量称为局部变量,有时也称为自动变量、临时变量或堆栈变量。局部变量的作用域是所在的方法或代码块,当程序执行流......