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

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

反射机制介绍

网络异常,图片无法展示
|

什么是反射

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

反射的作用

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

创建对象过程

Java创建对象的三个阶段

2345_image_file_copy_400.jpg

创建对象时内存结构

Users user = new Users();

2345_image_file_copy_401.jpg

实际上,我们在加载任何一个类时都会在方法区中建立“这个类对应 的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);
   }
}

获取类的构造方法

方法介绍

image.png
方法使用

修改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());
   }
}

获取类的成员变量

方法介绍

image.png

方法使用

修改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);
   }
}

获取类的方法

方法介绍

image.png

方法使用

修改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、处理注解。


目录
相关文章
|
3月前
|
监控 Cloud Native Java
Quarkus 云原生Java框架技术详解与实践指南
本文档全面介绍 Quarkus 框架的核心概念、架构特性和实践应用。作为新一代的云原生 Java 框架,Quarkus 旨在为 OpenJDK HotSpot 和 GraalVM 量身定制,显著提升 Java 在容器化环境中的运行效率。本文将深入探讨其响应式编程模型、原生编译能力、扩展机制以及与微服务架构的深度集成,帮助开发者构建高效、轻量的云原生应用。
440 44
|
3月前
|
安全 Java API
Java Web 在线商城项目最新技术实操指南帮助开发者高效完成商城项目开发
本项目基于Spring Boot 3.2与Vue 3构建现代化在线商城,涵盖技术选型、核心功能实现、安全控制与容器化部署,助开发者掌握最新Java Web全栈开发实践。
439 1
|
4月前
|
安全 Java 编译器
new出来的对象,不一定在堆上?聊聊Java虚拟机的优化技术:逃逸分析
逃逸分析是一种静态程序分析技术,用于判断对象的可见性与生命周期。它帮助即时编译器优化内存使用、降低同步开销。根据对象是否逃逸出方法或线程,分析结果分为未逃逸、方法逃逸和线程逃逸三种。基于分析结果,编译器可进行同步锁消除、标量替换和栈上分配等优化,从而提升程序性能。尽管逃逸分析计算复杂度较高,但其在热点代码中的应用为Java虚拟机带来了显著的优化效果。
171 4
|
4月前
|
Java API Maven
2025 Java 零基础到实战最新技术实操全攻略与学习指南
本教程涵盖Java从零基础到实战的全流程,基于2025年最新技术栈,包括JDK 21、IntelliJ IDEA 2025.1、Spring Boot 3.x、Maven 4及Docker容器化部署,帮助开发者快速掌握现代Java开发技能。
967 1
|
5月前
|
人工智能 Java
Java多任务编排技术
JDK 5引入Future接口实现异步任务处理,但获取结果不够灵活。Java 8新增CompletableFuture,实现异步任务编排,支持流式处理、多任务组合及异常处理,提升执行效率与代码可读性,简化并发编程复杂度。
139 0
|
4月前
|
Java 测试技术 API
2025 年 Java 开发者必知的最新技术实操指南全览
本指南涵盖Java 21+核心实操,详解虚拟线程、Spring Boot 3.3+GraalVM、Jakarta EE 10+MicroProfile 6微服务开发,并提供现代Java开发最佳实践,助力开发者高效构建高性能应用。
785 4
|
3月前
|
安全 Cloud Native Java
Java 模块化系统(JPMS)技术详解与实践指南
本文档全面介绍 Java 平台模块系统(JPMS)的核心概念、架构设计和实践应用。作为 Java 9 引入的最重要特性之一,JPMS 为 Java 应用程序提供了强大的模块化支持,解决了长期存在的 JAR 地狱问题,并改善了应用的安全性和可维护性。本文将深入探讨模块声明、模块路径、访问控制、服务绑定等核心机制,帮助开发者构建更加健壮和可维护的 Java 应用。
306 0
|
4月前
|
JavaScript 安全 前端开发
Java开发:最新技术驱动的病人挂号系统实操指南与全流程操作技巧汇总
本文介绍基于Spring Boot 3.x、Vue 3等最新技术构建现代化病人挂号系统,涵盖技术选型、核心功能实现与部署方案,助力开发者快速搭建高效、安全的医疗挂号平台。
269 3
|
5月前
|
存储 Java Linux
操作系统层面视角下 Java IO 的演进路径及核心技术变革解析
本文从操作系统层面深入解析Java IO的演进历程,涵盖BIO、NIO、多路复用器及Netty等核心技术。分析各阶段IO模型的原理、优缺点及系统调用机制,探讨Java如何通过底层优化提升并发性能与数据处理效率,全面呈现IO技术的变革路径与发展趋势。
133 2
|
5月前
|
安全 Java 微服务
Java 最新技术和框架实操:涵盖 JDK 21 新特性与 Spring Security 6.x 安全框架搭建
本文系统整理了Java最新技术与主流框架实操内容,涵盖Java 17+新特性(如模式匹配、文本块、记录类)、Spring Boot 3微服务开发、响应式编程(WebFlux)、容器化部署(Docker+K8s)、测试与CI/CD实践,附完整代码示例和学习资源推荐,助你构建现代Java全栈开发能力。
664 1