Java基础深化和提高 ---- 反射技术

news2024/10/7 15:22:11

目录

反射机制介绍

 什么是反射

 反射的作用

创建对象过程 

Java创建对象的三个阶段

 创建对象时内存结构

反射的具体实现 

 创建Users类

通过getClass()方法获取Class对象

通过.class 静态属性获取Class对象

通过forName()获取Class对象

获取类的构造方法

通过构造方法创建对象

获取类的成员变量

方法介绍

 方法使用

获取成员变量

操作成员变量

获取类的方法

方法介绍

 方法使用

获取方法

调用方法

获取类的其他信息

反射应用案例

反射机制的效率

反射机制的效率测试 

setAccessible方法

本章总结


反射机制介绍

 什么是反射

Java 反射机制是Java语言一个很重要的特性,它使得Java具有了“动 态性”。在Java程序运行时,对于任意的一个类,我们能不能知道这 个类有哪些属性和方法呢?对于任意的一个对象,我们又能不能调 用它任意的方法?答案是肯定的!这种动态获取类的信息以及动态 调用对象方法的功能就来自于Java 语言的反射(Reflection)机 制。

 反射的作用

简单来说两个作用,RTTI(运行时类型识别)和DC(动态创建)。 我们知道反射机制允许程序在运行时取得任何一个已知名称的class 的内部信息,包括其modifiers(修饰符),fields(属性),methods(方 法)等,并可于运行时改变fields内容或调用methods。那么我们便 可以更灵活的编写代码,代码可以在运行时装配,无需在组件之间 进行源代码链接,降低代码的耦合度;还有动态代理的实现等等; 但是需要注意的是反射使用不当会造成很高的资源消耗!

创建对象过程 

Java创建对象的三个阶段

 创建对象时内存结构

Users user = new Users();

 实际上,我们在加载任何一个类时都会在方法区中建立“这个类对应 的Class对象”,由于“Class对象”包含了这个类的整个结构信息,所 以我们可以通过这个“Class对象”来操作这个类。 我们要使用一个类,首先要加载类;加载完类之后,在堆内存中, 就产生了一个 Class 类型的对象(一个类只有一个 Class 对象), 这个对象就包含了完整的类的结构信息。我们可以通过这个对象知 道类的结构。这个对象就像一面镜子,透过这个镜子可以看到类的 结构,所以,我们形象的称之为:反射。 因此,“Class对象”是反射 机制的核心。

反射的具体实现 

获取Class对象的三种方式

 1、通过getClass()方法;

 2、通过.class 静态属性;

 3、通过Class类中的静态方法forName();

 创建Users类

public class Users {
    private String username;
    private int userage;
    public String getUsername() {
        return username;
      }
   public void setUsername(String username)
     {
        this.username = username;
     }
   public int getUserage() {
        return userage;
      }
    public void setUserage(int userage) {
        this.userage = userage;
   }
}

通过getClass()方法获取Class对象

* 通过getClass()方法获取该类的Class对象
*/
public class GetClass1 {
    public static void main(String[] args) {
        Users users = new Users();
        Users users1 = new Users();
        Class clazz = users.getClass();
        System.out.println(clazz);
        System.out.println(clazz.getName());
        System.out.println(users.getClass() == users1.getClass());
   }
}

通过.class 静态属性获取Class对象

/**
* .class静态属性获取Class对象
*/
public class GetClass2 {
    public static void main(String[] args) {
        Class clazz = Users.class;
        Class clazz2 = Users.class;
        System.out.println(clazz);
        System.out.println(clazz.getName());
        System.out.println(clazz == clazz2);
   }
}

通过forName()获取Class对象

/**
* 通过Class.forName("class Name")获取Class对象
*/
public class GetClass3 {
    public static void main(String[] args)throws Exception {
        Class clazz = Class.forName("com.bjsxt.Users");
        Class clazz2 = Class.forName("com.bjsxt.Users");
        System.out.println(clazz);
        System.out.println(clazz.getName());
        System.out.println(clazz == clazz2);
   }
}

获取类的构造方法

方法介绍

 方法使用

修改Users类

public class Users {
    private String username;
    private int userage;
    public Users(){}
    public Users(String username,int userage){
        this.username= username;
        this.userage=userage;
   }
   
 public  Users(String username){
        this.username= username;
   }
   
 private Users(int userage){
        this.userage = userage;
   }
   
 public String getUsername() {
        return username;
   }
    
 public void setUsername(String username)
   {
        this.username = username;
   }
    
 public int getUserage() {
        return userage;
   }
 public void setUserage(int userage) {
        this.userage = userage;
   }
}

获取构造方法

public class GetConstructor {
    public static void main(String[] args)throws Exception {
        Class clazz = Users.class;
        Constructor[]  arr = clazz.getDeclaredConstructors();
        for(Constructor c:arr){
            System.out.println(c);
       }
        System.out.println("---------------------");
        Constructor[]  arr1 = clazz.getConstructors();
        for(Constructor c:arr1){
            System.out.println(c);
       }
        System.out.println("------------------------");
        Constructor c =   clazz.getDeclaredConstructor(int.class);
        System.out.println(c);
        System.out.println("------------------------");
        Constructor c1 =   clazz.getConstructor(null);
        System.out.println(c1);
   }
}

通过构造方法创建对象

public class GetConstructor2 {
    public static void main(String[] args)throws Exception {
        Class clazz = Users.class;
        Constructor constructor = clazz.getConstructor(String.class,int.class);
        Object o = constructor.newInstance("OldLu",18);
        Users users = (Users)o;
      System.out.println(users.getUsername()+"\t"+ users.getUserage());
   }
}

获取类的成员变量

方法介绍

 方法使用

修改Users类

public class Users {
    private String username;
    public int userage;
    public Users(){
   }
    
    public Users(String username,int userage){
        this.username= username;
        this.userage=userage;
      }
    
    public  Users(String username){
        this.username= username;
      }
    
    private Users(int userage){
        this.userage = userage;
      }

    public String getUsername() {
        return username;
      }
    public void setUsername(String username)
      {
        this.username = username;
      }
    public int getUserage() {
        return userage;
      }
    public void setUserage(int userage) {
        this.userage = userage;
   }
}

获取成员变量

public class GetField {
    public static void main(String[] args)throws Exception {
        Class clazz = Users.class;
        Field[] fields = clazz.getFields();
        for(Field f:fields){
            System.out.println(f);
            System.out.println(f.getName());
        }
        System.out.println("------------------------");
        Field[] fields2 =clazz.getDeclaredFields();
        for(Field f:fields2){
            System.out.println(f);
            System.out.println(f.getName());
       }
        System.out.println("------------------------");
        Field field = clazz.getField("userage");
        System.out.println(field);
        System.out.println("---------------------");
        Field field1 = clazz.getDeclaredField("username");
        System.out.println(field1);
   }
}

操作成员变量

public class GetField2 {
    public static void main(String[] args)throws Exception {
        Class clazz = Users.class;
        Field field = clazz.getField("userage");
        //对象实例化
        Object obj = clazz.newInstance();
        //为成员变量赋予新的值
        field.set(obj,18);
        //获取成员变量的值
        Object o = field.get(obj);
        System.out.println(o);
   }
}

获取类的方法

方法介绍

 方法使用

修改Users类

public class Users {
    private String username;
    public int userage;
    public Users(){ }
    public Users(String username,int userage){
        this.username= username;
        this.userage=userage;
      }
    public  Users(String username){
        this.username= username;
      }
    private Users(int userage){
        this.userage = userage;
      }
    public String getUsername() {
        return username;
      }
    public void setUsername(String username)
      {
        this.username = username;
      }
    public int getUserage() {
        return userage;
      }
    public void setUserage(int userage) {
        this.userage = userage;
      }
    private void suibian(){
        System.out.println("Hello Oldlu");
   }
}

获取方法

public class GetMethod {
    public static void main(String[] args)throws Exception{
        Class clazz = Users.class;
        Method[] methods = clazz.getMethods();
        for(Method m: methods){
            System.out.println(m);
            System.out.println(m.getName());
       }
        System.out.println("---------------------------");
        Method[] methods2 = clazz.getDeclaredMethods();
        for(Method m: methods2){
            System.out.println(m);
            System.out.println(m.getName());
       }
        System.out.println("--------------------------");
        Method method = clazz.getMethod("setUserage", int.class);
        System.out.println(method.getName());
        System.out.println("--------------------------");
        Method method1 = clazz.getDeclaredMethod("suibian");
        System.out.println(method1.getName());
   }
}

调用方法

public class GetMethod2 {
    public static void main(String[] args)throws  Exception {
        Class clazz = Users.class;
        Method method = clazz.getMethod("setUsername",String.class);
         //实例化对象
        Object obj = clazz.getConstructor(null).newInstance();
        //通过setUserName赋值
        method.invoke(obj,"oldlu");
        //通过getUserName获取值
        Method method1 = clazz.getMethod("getUsername");
        Object value = method1.invoke(obj);
        System.out.println(value);
   }
}

获取类的其他信息

public class GetClassInfo {
    public static void main(String[] args) {
        Class clazz = Users.class;
        //获取类名
        String className = clazz.getName();
        System.out.println(className);
        //获取包名
        Package p = clazz.getPackage();
        System.out.println(p.getName());
        //获取超类
        Class superClass = clazz.getSuperclass();
        System.out.println(superClass.getName());
        //获取该类实现的所有接口
        Class[] interfaces = clazz.getInterfaces();
        for(Class inter:interfaces){
           System.out.println(inter.getName());
       }
   }
}

反射应用案例

需求:根据给定的方法名顺序来决定方法的执行顺序。

class Reflect {
    public void method1(){
      System.out.println("Method1.......");
   }
    public void method2(){
       System.out.println("Method2.......");
   }
    public void method3(){
       System.out.println("Method3.......");
   }
}
public class ReflectDemo {
    public static void main(String[] args)throws Exception {
        Reflect rd = new Reflect();
        if(args != null && args.length > 0){
            //获取ReflectDemo的Class对象
            Class clazz = rd.getClass();
            //通过反射获取ReflectDemo下的所有方法
            Method[] methods = clazz.getMethods();
            for(String str :args){
                for(int i=0;i<methods.length;i++){ if(str.equalsIgnoreCase(methods[i].getName())){
                      methods[i].invoke(rd);
                        break;
                   }
               }
           }
       }else{
            rd.method1();
            rd.method2();
            rd.method3();
       }
   }
}

反射机制的效率

由于Java反射是要解析字节码,将内存中的对象进行解析,包括了 一些动态类型,而JVM无法对这些代码进行优化。因此,反射操作 的效率要比那些非反射操作低得多! 接下来我们做个简单的测试来直接感受一下反射的效率。

反射机制的效率测试 

public class Test{
    public static void main(String[] args) {
        try {
            //反射耗时
            Class clazz = Class.forName("com.bjsxt.Users");
            Users users = (Users) clazz.getConstructor(null).newInstance();
            long reflectStart = System.currentTimeMillis();
            Method method = clazz.getMethod("setUsername", String.class);
            for(int i=0;i<100000000;i++){
               method.invoke(users,"oldlu");
           }
            long reflectEnd = System.currentTimeMillis();
            //非反射方式的耗时
            long start = System.currentTimeMillis();
            Users u = new Users();
            for(int i=0;i<100000000;i++){
                u.setUsername("oldlu");
           }
            long end = System.currentTimeMillis();
            System.out.println("反射执行时 间:"+(reflectEnd - reflectStart)); System.out.println("普通方式执行时间:"+(end - start));
       } catch (Exception e) {
            e.printStackTrace();
       }
   }
}

setAccessible方法

setAccessible()方法: setAccessible是启用和禁用访问安全检查的开关。值为 true 则指示 反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指 示反射的对象应该实施 Java 语言访问检查;默认值为false。 由于JDK的安全检查耗时较多.所以通过setAccessible(true)的方式关 闭安全检查就可以达到提升反射速度的目的。

public class Test2 {
    public static void main(String[] args)throws Exception {
        Users users = new Users();
        Class clazz = users.getClass();
        Field field = clazz.getDeclaredField("username");
        //忽略安全检查
        field.setAccessible(true);
        field.set(users,"oldlu");
        Object object = field.get(users); System.out.println(object);
        System.out.println("-----------------------------");
        Method method = clazz.getDeclaredMethod("suibian");
        method.setAccessible(true);
        method.invoke(users);
   }
}

本章总结

Java 反射机制是Java语言一个很重要的特性,它使得Java具有了 “动态性”。

反射机制的优点:

    1、更灵活。

    2、更开放。

反射机制的缺点:

    1、降低程序执行的效率。

    2、增加代码维护的困难。

获取Class类的对象的三种方式:

   1、运用getClass()。

   2、运用.class 语法。

   3、运用Class.forName()(最常被使用)。

反射机制的常见操作

   1、动态加载类、动态获取类的信息(属性、方法、构造器)。

   2、动态构造对象。

   3、动态调用类和对象的任意方法。

   4、动态调用和处理属性。

   5、 获取泛型信息。

   6、处理注解。

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

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

相关文章

设计模式之享元模式(十)

目录 1. 享元模式概述 2. 享元模式在Integer中的应用 1. 享元模式概述 享元模式&#xff08;Flyweight Pattern&#xff09; 也叫 蝇量模式&#xff0c;运用共享技术有效地支持大量细粒度的对象。简单来说就是共享对象。 享元模式能够解决重复对象的内存浪费的问题&#xff…

Python3,os模块还可以这样玩,自动删除磁盘文件,非必要切勿操作。

删除磁盘下所有的文件1、引言2、代码实战2.1 模块介绍2.2 获取盘符2.3 获取盘符下的目录2.3.1 os.listdir()2.3.2 os.environ2.3.3 os.getenv()2.4 删除文件2.4.1 删除指定文件下文件2.4.2 删除所有文件下文件3、总结1、引言 小屌丝&#xff1a;鱼哥&#xff0c; 请教你个问题…

Flink基础篇(基础算子+WaterMarker)

Flink高可用HA 依赖于zkFlink ON Yarn两种模式Session模式Per-Job模式前置说明Flink原理数据在两个operator算子之间传递的时候有两种模式&#xff1a;Operator ChainTaskSlot And SharingFlink执行图&#xff08;ExecutionGraph&#xff09;APISourceTransformationSink控制台…

【图像识别-车牌识别】基于BP神经网络求解车牌识别问题含GUI界面和报告

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

11个销售心理学方法,帮你搞定客户!

销售心理学中&#xff0c;站在客户的角度&#xff0c;客户都会有以下几个疑问&#xff1a; 1、你是谁&#xff1f; 2、你要跟我介绍什么&#xff1f; 3、你介绍的产品和服务对我有什么好处&#xff1f; 4、如何证明你介绍的是真实的&#xff1f; 5、为什么我要跟你买&…

Linux学习之expect操作详解

一、expect安装介绍 1.expect命令安装 安装语句:yum install expect 2.expect命令含义 expect是一种脚本语言&#xff0c;它能够代替人工实现与终端的交互&#xff0c;主要应用于执行命令和程序时&#xff0c;系统以交互形式要求输入指定字符串&#xff0c;实现交互通信。 …

疟原虫蛋白复合物疫苗科研

疟疾是一种蚊媒疾病&#xff0c;感染者通常会出现发烧、发冷和流感样疾病。如果不及时治疗&#xff0c;严重者甚至会危及生命。世卫组织新近发布的数据表明&#xff0c;2019 年全球估计发生 2.29 亿疟疾病例&#xff0c;死于该病的人数超过 40 万例。 图 1. 2000 年有病例的国…

Flutter 应用程序中的 Quick Actions

Flutter 应用程序中的 Quick Actions 原文 https://medium.com/vijay-r/quick-actions-in-flutter-app-75b63acc420b 前言 在这篇文章中&#xff0c;我们将讨论如何添加 Quick Actions 在我们的 Flutter 应用程序&#xff0c;使我们的应用程序更加友好的用户。 正文 插件 quick…

LVM逻辑卷

要求&#xff1a;在系统下做LVM逻辑卷2G&#xff0c;并将LVM进行扩容到5G 操作环境&#xff1a;7.8.2003 [rootlocalhost ~]# lsblk #列出所有可用块设备信息 我们使用vdb和vdc两块硬盘做lvm 先将一个盘进行分区&#xff08;/dev/vdb&#xff09; [r…

Leetcode808. 分汤

文章目录题目链接题目大意解题思路代码(C)动态规划记忆化搜索题目链接 点我(^_^) 题目大意 注意不是两个概率加和除以2 解题思路 考虑动态规划&#xff0c;因为汤的分配都是以 25 的倍数进行分配的&#xff0c;所以这里把 25 ml 的汤看作一份&#xff0c;总的份数⌈汤的体…

A-Level经济例题解析及练习Analysis of Tax

今日知识点&#xff1a;Analysis of Tax 例题A. Compute consumer surplus, producer surplus, and total surplus without a tax. B. If $100 tax per ticket, compute consumer surplus, producer surplus, tax revenue, total surplus, and deadweight loss.解析下面我们为大…

搭载北京君正X2000主控芯片的成功案例

汉王e典笔S20 Plus搭载北京君正研发的X2000多核异构跨界处理器。X2000多核异构跨界处理器主要面向于智能音频、图像识别、智能家电、智能家居、智能办公等五大领域。CPU采取三核结构&#xff0c;搭载双XBurst2&#xff0c;主频1.2GHz&#xff0c;跨界第三核XBurst0(240MHz)&…

Linux--进程概念

前言&#xff1a; 在学习操作系统的过程中&#xff0c;我们常常能听到进程这一概念以及相关的一些知识。例如什么是父进程&#xff0c;什么是子进程&#xff0c;如何创建子进程&#xff0c;如何杀死进程等。这些知识后面会一一介绍&#xff0c;在迈入学习进程的第一步我只需要知…

[附源码]java毕业设计校园二手交易平台的设计

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

养殖废水总氮超标的解决方法

养殖废水除总氮。入水是100mg/L&#xff0c;处理水量大概在3T/H&#xff0c;要求养殖废水总氮小于5PPM。 生化前置过滤树脂的工艺&#xff0c;通过阳树脂中含有的阳离子会与水中的游离氨&#xff08;NH3&#xff09;和铵离子&#xff08;NH4&#xff09;进行交换&#xff0c;将…

2.15 这样的小红书图片内容,最容易“踩雷”!【玩赚小红书】

1、笔记中所有图片只展示一件单品 这类内容有可能会被系统判定为广告&#xff0c;或被用户怀疑为软广而举报。据介绍&#xff0c;小红书平台上的用户对软广的接受度较低&#xff0c;这类内容时常因为被举报而限流。 小红书引入“生态官”维护社区内容后&#xff0c;生态官也会…

三层vlan实验

目录 实验拓扑 实验需求 实验解法 5&#xff0c;按照图示配置 IP 地址&#xff0c;其中只有SW1需要配置三层vlan地址&#xff0c;电脑设备为DHCP获取地址 6&#xff0c;在sw1配置DHCP动态地址池塘&#xff0c;DNS为114.114.114.114 7&#xff0c;各台电脑通过交换机划分不…

你的系统如何支撑高并发?大佬手写高并发架构设计笔记帮你圆满回答!

开篇&#xff0c;我们聊聊大量同学问我的一个问题&#xff0c;面试的时候被问到一个让人特别手足无措的问题&#xff1a;你的系统如何支撑高并发&#xff1f; 大多数同学被问到这个问题压根儿没什么思路去回答&#xff0c;不知道从什么地方说起&#xff0c;其实本质就是没经历…

m虚拟MIMO系统的配对调度算法的matlab仿真,对比Random配对,Orthogonal配对以及Deteminant配对

目录 1.算法概述 2.仿真效果预览 3.MATLAB部分代码预览 4.完整MATLAB程序 1.算法概述 利用多输入多输出&#xff08;MIMO&#xff0c;Multiple InputMultiple Output&#xff09;技术通过空间复用能够显著的提高通信系统的容量&#xff0c;并可以很好的缓解时/频资源日益紧…

BCN衍生物:endo-BCN-PEG4-TAMRA/Palmitic/DSPE

凯新生物公司小编分享&#xff1a;endo-BCN-PEG4-TAMRA &#xff0c;endo-BCN-PEG4-Palmitic&#xff0c;endo-BCN-PEG4-DSPE这几种的物理相关数据。 1、endo-BCN-PEG4-TAMRA 四甲基罗丹明&#xff08;TAMRA&#xff09;-叠氮化物是一种化学探针&#xff0c;用于直接在活细胞中…