Java的反射机制与实用操作

news/2024/5/19 4:01:01 标签: java, 反射

JavaWeb学习大纲传送门

本章学习目录

  • 问题的引出:我们如何动态的调用类,从而实现工具类的多用性或者说是通用性呢?
  • 问题的解决:Java的反射机制能有效地实现
  • 页内目录
    一,Java反射机制的基本介绍
    二,Java反射机制的基本功能
    三,Java反射机制的原理
    四,Java反射机制的实用操作
    五,Java反射机制的意义
    六,Java反射机制的弊端

一,Java反射机制的基本介绍

  • Java的反射机制(reflection):是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。
  • 尽管Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection 这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。大概意思就是,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。这种“看透class”的能力被称为introspection(内省、内观、反省)。Reflectionintrospection是经常被并提的两个术语。

二,Java反射机制的基本功能

  • 主要提供了以下重要功能
    1. 在运行时判断任意一个对象所属的类
    2. 在运行时构造任意一个类的对象
    3. 在运行时判断任意一个类所具有的成员变量和方法
    4. 在运行时调用任意一个对象的方法;生成动态代理。

三,Java反射机制的原理

  • 反射机制的原理:对于一个字节码文件**.class**,虽然我们对该字节码文件一无所知,但该文件本身却记录了许多信息。Java在将.class字节码文件载入时,JVM将产生一个java.lang.Class对象代表该 .class 字节码文件,从该Class对象中可以获得类的许多基本信息,这就是反射机制
  • 反射机制所需的类主要有java.lang包中的Class类java.lang.reflect包
  • 要使用反射必须先拿到一个类一个类的的Class对象
    Class类:在反射中有一个核心类java.lang.Class类,该类表示的是类或接口的字节码对象.
  • 反射java.lang.reflect中都有相对应的类:
    1. Field类:对应类中的属性
      方法:
      1. 根据属性名获得一个属性对象:字节码对象.getDeclaredField("属性名");
      2. 获取本类全部属性:字节码对象.getDeclaredFields();
      3. 根据属性名获取本类及父类中public修饰的属性:字节码对象.getField(“属性名”);
      4. 获取本类及父类中public修饰的全部属性:字节码对象.getFields();
      5. 得到方法返回的属性对象可以调用获得属性类型方法:属性对象.getType()
      6. 得到方法返回的属性对象可以调用获得修饰符类型代号方法:属性对象.getModifiers();
      7. 得到方法返回的属性对象可以调用获得修饰符类型方法:Modifier.toString(属性对象.getModifiers());
      8. 得到方法返回的属性对象可以调用获得属性名方法:属性对象.getName();
    2. Method类:对应类中的方法
      方法:
      1. 根据方法名和参数列表获得一个方法:字节码对象.getDeclaredMethod("",基本类型.class);
      2. 获得本类的所有方法:字节码对象.getDeclaredMethods();
      3. 本类与父类的方法获得同field
      4. 调用类中的方法(对于根据方法名和参数列表获得一个方法):根据方法名和参数列表获得一个方法的对象.invoke(该字节码对象的实例,为参数赋的值);
    3. Modifier类:对应类中的修饰符
      方法:
      1. 无非就是获得对象的数字类型:获得的对象.getModifiers()
      2. 转化为真正的修饰符:Modifier.toString(获得的对象.getModifiers());
    4. Constructor类:对应类中的构造器
      方法:
      1. 获得某一个构造方法:userClass.getDeclaredConstructors(基本类型.class);
      2. 获得所有构造方法:userClass.getDeclaredConstructors();
    5. 就害怕你说方法知道了,怎么确定返回的是什么呢!
      1. 根据方法查看:
        流程
      2. 快捷键生成,点击该部分任意一处使用快捷键alt+enter, 就生成了它的返回值类型和流程流程
        流程

四,Java反射机制的实用操作

  • 获得一个类的Class对象(字节码对象)和创建对象(含有参)的方式:
java">        //1,根据类的完整路径获取字节码对象
        Class userCla1=Class.forName("com.jazhong.reflect.User");
        //2,通过类名获取类的字节码文件
        Class userCla2=User.class;
        //3,通过对象名获取该对象的所对应的字节码文件
        User user=new User();
        Class userCla3 = user.getClass();
        //创建对象   jdk高版本用userCla.getDeclatedConstructor().newInstance();
        Object obj = userCla.newInstance();
        //有参先要获得有参的构造器然后创建
        //获得有参数的构造器
        Constructor constructor = userClass.getDeclaredConstructor(int.class, String.class, String.class);
        //利用获得的构造方法对象来创建类的对象
        Object obj1 = constructor.newInstance(1, "xiaohua", "123456");
  • 使用反射操作类中的属性,获得类中的所有属性
java">        //获得字节码对象
        Class userClass = User.class;
        //获得类中的所有属性
        Field[] declaredFields = userClass.getDeclaredFields();
        //使用循环遍历,并获得每个属性的详情
        for (Field field:declaredFields){
            //获得属性名
            String name = field.getName();
            //获得属性的类型
            Class type = field.getType();
            //获得属性的修饰符,修饰符modifiersnum得到的是数字
            int modifiersnum = field.getModifiers();
            //运用Modifier.toString方法转换成修饰符
            String modifiers = Modifier.toString(modifiersnum);
            System.out.println("属性的修饰符代号"+modifiersnum+"属性的修饰符"+modifiers+"属性的类型"+type+"属性名"+name);
        }
  • 获得指定的属性并调用该属性为该属性赋值及获取值
java">        //获取User类的字节码文件
        Class userCla= User.class;
        //根据属性名获取一个属性对象Field
        Field field=userCla.getDeclaredField("username");
        //创建类的对象
        //userCla.newInstance();不能用的,因为你的jdk版本高,所以说可以写成新版的写:userCla.getDeclatedConstructor().newInstance();
        Object obj=userCla.newInstance();
        //调用属性 参1:对象(调用的对象的属性)
        //        参2:值(为属性要设置的值)
        field.set(obj,"admin");//等同于 obj.field="admin"
        System.out.println((String) field.get(obj));
  • 获得类中的方法细节
java">        //获得user类的字节码对象
        Class userClass = User.class;
        //获得userCla的所有方法
        Method[] Methods = userClass.getDeclaredMethods();
        //遍历methods
        for (Method method:Methods){
            //获得方法修饰符
            int modifiers = method.getModifiers();
            String modifierStr = Modifier.toString(modifiers);
            //获得方法返回类型
            Class returnType = method.getReturnType();
            //获得方法名
            String methodName = method.getName();
            //获得参数列表
            Class[] parameterTypes = method.getParameterTypes();
            //获得方法抛出的异常类型
            Class[] exceptionTypes = method.getExceptionTypes();
            //获得方法的所有注解
            Annotation[] annotations = method.getDeclaredAnnotations();
            System.out.println(modifierStr+" "+returnType+" "+methodName);
            System.out.println("参数列表:");
            for(Class paramClass :parameterTypes){
                System.out.println(paramClass);
            }
            System.out.println("异常列表:");
            for(Class exType : exceptionTypes){
                System.out.println(exType);
            }
            System.out.println("注解列表:");
            for(Annotation annotation :annotations ){
                System.out.println(annotation);
            }
            System.out.println("***************");
        }
  • 根据方法名和方法的参数列表获得一个方法对象,并调用该方法
java">        //获得user类的字节码对象
        Class userCla= User.class;
        //根据方法名和参数列表获得一个方法对象
        Method method=userCla.getDeclaredMethod("setUsername",String.class);
        //创建对象   jdk高版本用userCla.getDeclatedConstructor().newInstance();
        Object obj = userCla.newInstance();
        //调用方法setUsername,为参数String赋值-笑傲-
        method.invoke(obj,"笑傲");//等同于obj.method(")
        //获得get方法
        Method getmethod=userCla.getDeclaredMethod("getUsername");
        //调用方法,返回结果
        Object obj1 = getmethod.invoke(obj);
        System.out.println(obj1);
  • 使用反射获得类中的构造方法
java">        //创建class对象
        Class<User> userClass = User.class;
        //获得类中的所有构造方法
        java.lang.reflect.Constructor<?>[] declaredConstructors = userClass.getDeclaredConstructors();
        //遍历数组,获得每个构造器的详情
        for (Constructor constructor:declaredConstructors){
            //获得构造器方法的名字
            String name = constructor.getName();
            //获得构造方法的修饰符
            String modiferName = Modifier.toString(constructor.getModifiers());
            //获得参数列表
            Class[] parames = constructor.getParameterTypes();
            System.out.println(modiferName+""+name);
            //遍历参数列表
            for (Class param:parames){
                System.out.println(param);
            }
        }
  • 根据参数列表获得指定的构造器并利用该构造器创建对象
java">        Class userClass = User.class;
        //使用无参数的构造方法创建类的对象(即userClass对应的类的对象)
        //通过class对象调用无参构造方法创建对象
        //jdk新版本用userClass.getDeclatedConstructor().newInstance();
        Object obj = userClass.newInstance();
        //获得有参数的构造器
        Constructor constructor = userClass.getDeclaredConstructor(int.class, String.class, String.class);
        //利用获得的构造方法对象来创建类的对象
        Object obj1 = constructor.newInstance(1, "xiaohua", "123456");
        System.out.println(obj1);

五,Java反射机制的意义

  • 意义
    1. 反射机制极大的提高了程序的灵活性和扩展性,降低模块的耦合性,提高自身的适应能力。
    2. 通过反射机制可以让程序创建和控制任何类的对象,无需提前硬编码目标类。
    3. 使用反射机制能够在运行时构造一个类的对象、判断一个类所具有的成员变量和方法、调用一个对象的方法。
    4. 反射机制是构建框架技术的基础所在,使用反射可以避免将代码写死在框架中。
  • 总结:正是反射有以上的特征,所以它能动态编译和创建对象,极大的激发了编程语言的灵活性,强化了多态的特性,进一步提升了面向对象编程的抽象能力,因而受到编程界的青睐。

六,Java反射机制的特性

  • 反射机制带来了极大的灵活性及方便性,但反射也有缺点。反射机制的功能非常强大,但不能滥用。在能不使用反射完成的情况下,尽量不使用,原因:
    1. 性能问题:
      Java反射机制中包含了一些动态类型,所以Java虚拟机不能够对这些动态代码进行优化。因此,反射操作的效率要比正常操作效率低很多。我们应该避免在对性能要求很高的程序或经常被执行的代码中使用反射。而且,如何使用反射决定了性能的高低。如果它作为程序中较少运行的部分,性能将不会成为一个问题。
    2. 安全限制:
      使用反射通常需要程序的运行没有安全方面的限制。如果一个程序对安全性提出要求,则最好不要使用反射
    3. 程序健壮性:
      反射允许代码执行一些通常不被允许的操作,所以使用反射有可能会导致意想不到的后果。反射代码破坏了Java程序结构的抽象性,所以当程序运行的平台发生变化的时候,由于抽象的逻辑结构不能被识别,代码产生的效果与之前会产生差异。

注:本片文章对于百度文库中的反射讲解和所学进行的总结


http://www.niftyadmin.cn/n/1674814.html

相关文章

类里面的大括号{}加载顺序

一、序言 前几天遇到了一个类加载的顺序问题&#xff0c;废话不多说&#xff0c;直接上代码 二、问题 上代码&#xff1a; package com.hz.test;public class Demo2 {public static void main(String[] args) {new Son();new Son();} } class Father{//public static int i 0;p…

pdfstamper生成pdf无法显示汉字_这个pdf笔记神器,P事都能Peace

据说每个工作党都躲不开以下这些“P”事PS、PPT、PDFPDF作为一个兼容性特强的格式不管是工作文件还是读书学习不管是word、ppt还是jpg万物皆可转成pdf但当你想边看pdf边做笔记、整理知识点或者把内容梳理成思维导图的时候总是难免需要2个以上的软件过程中还得不停的切换窗口对记…

设置边框_css3如何设置边框颜色渐变?css3边框颜色渐变的两种实现方法

很多时候在开发网页的时候&#xff0c;可能因为一些原因需要为边框设置颜色渐变&#xff0c;那么该如何设置颜色边框渐变&#xff1f;本篇文章将为大家介绍使用css3设置边框颜色渐变的方法。程序猿的生活&#xff1a;web前端全栈资料粉丝福利&#xff08;面试题、视频、资料笔记…

DBUtil基于反射的进化版本

JavaWeb学习大纲传送门 本章学习目录 问题的引出&#xff1a;往日的工具类需要针对不同的环境做出适当的改变&#xff0c;这里由于&#xff0c;增删改已经实现通用&#xff0c;那么对于查询是否可以一个工具类多用呢&#xff1f;&#xff08;之前细讲过普通的DBUtil设置&…

oracle如果插入id重复不进行操作_动态SQL不绑定变量的影响

ORACLE可以用EXECUTE IMMEDIATE来执行动态SQL&#xff0c;但在动态SQL中如果涉及到变量&#xff0c;一定要使用USING方法来绑定变量&#xff0c;不能直接把变量拼接到SQL执行&#xff0c;否则会严重影响执行的性能。动态SQL不绑定变量&#xff0c;即直接拼接变量到SQL&#xff…

APUE读书笔记-18终端输入输出-03特殊输入字符

转载于:https://blog.51cto.com/quietheart/881097

浏览器界面下的基于JSP和servlet的数据的增删改查

JavaWeb学习大纲传送门 本章学习目录 问题的引出&#xff1a;学了提升作用域request篇和response篇&#xff0c;EL表达式&#xff0c;jsp标签库&#xff0c;反射我们怎样去应用呢&#xff1f; 问题的解决&#xff1a;针对于数据的增删改查的浏览器界面化&#xff0c;我们对它…

php : 文件及文件夹操作(创建、删除、移动、复制)

Talk is cheap, show you the code : <?php/*** 操纵文件类* */ class FileUtil {/*** 建立文件夹** param string $aimUrl* return viod*/function createDir($aimUrl) {$aimUrl str_replace(, /, $aimUrl);$aimDir ;$arr explode(/, $aimUrl);$result true;foreach …