Java反射机制

简介: Java反射机制

1.定义

java的反射(reflection)机制是在java运行状态中,对任意一个类,都能知道这个类的所有方法和属性。 对于任意一个对象, 都能够调用它的任意方法和属性, 也可以修改其部分信息。 这种动态获取值以及动态调用对象的方法就叫做java语言的反射机制

2.用途

  • 在日常中的三方应用开发过程中,经常会遇到某个类的某个成员变量,方法或者是属性是私有的,或者是只对系统应用开放, 这时候就可以利用java的反射机制来获取这些私有成员或者是方法。
  • 反射最重要的用途就是开发各种通用框架, 比如spring中,将所有的类bean交给spring容器管理,无论xml配置bean还是注解配置,当我们从容器中或缺bean来依赖注入时,容器就会读取配置, 而配置中给的就是类的信息 spring根据这些信息,创建那些bean,spirng就动态创建这些类。

3.反射基本信息

java程序中许多对象在运行玩的时候会出现两种类型,运行时类和编译时类,程序需要在运行时发现对象和类的真实信息。而通过反射程序就能判断出该对象和类属于哪些类。

4.反射相关的类

  • Class类:代表类的实体 在运行的java应用程序当中表示类和接口
  • Field类:代表类的成员变量(属性)
  • Method类:代表类的方法
  • Constructor类:代表类的构造方法

Class类

原理

代表类的实体,在运行的java程序中表示类和接口

java文件被编译之后,生成了.class文件,jvm此时就要去解读这个.class文件,被编译后的java文件,.class也被jvm解析为一个对象, 这个对象就是java.lang.Class。 这样,当程序在运行时,每个java文件就最终变成Class类对象的一个实例。我们通过java反射机制,应用到这个实例,就可以去获得甚至是修改这个类的属性和动作,是这个类成为一个动态的类

获取类的方法

方法

作用

getClassLoader()

获得类的加载器

getDeclaredClasses()

返回一个数组,数组中包含该类中所有类和接口类的对象(包括私有的)

forName(String className)

根据类名返回类的对象

newInstance()

创建类的实例

getName()

获得类的完整路径名字

获取属性的方法

方法

作用

getField(String name)

获得某个公有的属性对象

getFields()

获得所有公有的属性对象

getDeclaredField(String name)

获得某个属性对象

getDeclaredFields()

获得所有属性对象

获得类中构造器相关

方法

用途

getConstructor(Class...<?> parameterTypes)

获得该类中与参数类型匹配的公有构造方法

getConstructors()

获得该类的所有公有构造方法

getDeclaredConstructor(Class...<?> parameterTypes)

获得该类中与参数类型匹配的构造方法

getDeclaredConstructors()

获得该类所有构造方法

获得类中方法相关的方法

方法

用途

getMethod(String name, Class...<?> parameterTypes)

获得该类某个公有的方法

getMethods()

获得该类所有公有的方法

getDeclaredMethod(String name, Class...<?> parameterTypes)

获得该类某个方法

getDeclaredMethods()

获得该类所有方法

一个简单的例子

一个类:

class Student{
    //私有属性name
    private String name = "hello";
    //公有属性age
    public int age = 18;
    //不带参数的构造方法
    public Student(){
        System.out.println("Student()");
    }
    private Student(String name,int age) {
        this.name = name;
        this.age = age;
        System.out.println("Student(String,name)");
    }
    private void eat(){
        System.out.println("i am eat");
    }
    public void sleep(){
        System.out.println("i am pig");
    }
    private void function(String str) {
        System.out.println(str);
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

在进行反射之前我们首先需要拿到其需要反射的类的Class对象, 然后再利用反射机制进行相关操作:

获取Class对象的3中方法:

public class Main {
    public static void main(String[] args) throws ClassNotFoundException { // 受查异常
        Class<?> c1 = Class.forName("Student");  // 1
        Class<?> c2 = Student.class;  // 2
 
        Student student = new Student();
        Class<?> c3 = student.getClass();
 
        System.out.println(c1 == c2);
        System.out.println(c3 == c2);
        System.out.println(c1 == c3);
    }
}

结果输出3个true, 所以, 不管是哪种方法获取的Class对象, 结果都是相同的.

调用不带参数的构造方法

public class Main {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        Class<?> c2 = Student.class;  
        Student student = (Student) c2.newInstance();
    }
}

这里的newInstance()方法返回的是一个Object类, 这里将其强制转换为Student类.

调用私有构造方法

public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
        Class<?> c2 = Class.forName("Student");  // 2
        Constructor<?> constructor = c2.getDeclaredConstructor(String.class, int.class);
        constructor.setAccessible(true);
        Student student = (Student) constructor.newInstance("libo",19);
        System.out.println(student);
    }

结果:

反射修改属性

public class Main {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException {
        Class<?> c1 = Class.forName("Student");
        Field field = c1.getDeclaredField("name");
        field.setAccessible(true);
        // 使用set改变属性
        Student student = (Student) c1.newInstance();
        field.set(student,"bozimeimei");
        System.out.println(student);
    }
}

反射调用方法

public class Main {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        Class<?> c1 = Class.forName("Student");
        Method method = (Method) c1.getDeclaredMethod("function", String.class);
        method.setAccessible(true);
        Student student = (Student) c1.newInstance();
        method.invoke(student, "hello bozimeimei");
    }
}

反射的优缺点

优点

1. 对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法

2. 增加程序的灵活性和扩展性,降低耦合性,提高自适应能力

3. 反射已经运用在了很多流行框架如:Struts、Hibernate、Spring 等等。

缺点

1. 使用反射会有效率问题。会导致程序效率降低。

2. 反射技术绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂 。


目录
相关文章
|
4月前
|
设计模式 人工智能 安全
AQS:Java 中悲观锁的底层实现机制
AQS(AbstractQueuedSynchronizer)是Java并发包中实现同步组件的基础工具,支持锁(如ReentrantLock、ReadWriteLock)和线程同步工具类(如CountDownLatch、Semaphore)等。Doug Lea设计AQS旨在抽象基础同步操作,简化同步组件构建。 使用AQS需实现`tryAcquire(int arg)`和`tryRelease(int arg)`方法以获取和释放资源,共享模式还需实现`tryAcquireShared(int arg)`和`tryReleaseShared(int arg)`。
234 32
AQS:Java 中悲观锁的底层实现机制
|
2月前
|
人工智能 缓存 安全
Java中的反射机制:深入探索与应用
Java反射机制是程序运行时动态获取类信息并操作类成员的特性,具备高度灵活性,但也伴随性能与安全风险。本文详解反射的基本用法、高级应用及最佳实践,助你掌握这一强大工具的正确使用方式。
134 0
|
4月前
|
人工智能 Java 关系型数据库
Java——SPI机制详解
SPI(Service Provider Interface)是JDK内置的服务提供发现机制,主要用于框架扩展和组件替换。通过在`META-INF/services/`目录下定义接口实现类文件,Java程序可利用`ServiceLoader`动态加载服务实现。SPI核心思想是解耦,允许不同厂商为同一接口提供多种实现,如`java.sql.Driver`的MySQL与PostgreSQL实现。然而,SPI存在缺陷:需遍历所有实现并实例化,可能造成资源浪费;获取实现类方式不够灵活;多线程使用时存在安全问题。尽管如此,SPI仍是Java生态系统中实现插件化和模块化设计的重要工具。
156 0
|
2月前
|
人工智能 前端开发 安全
Java开发不可不知的秘密:类加载器实现机制
类加载器是Java中负责动态加载类到JVM的组件,理解其工作原理对开发复杂应用至关重要。本文详解类加载过程、双亲委派模型及常见类加载器,并介绍自定义类加载器的实现与应用场景。
185 4
|
2月前
|
人工智能 安全 Java
掌握Java反射:在项目中高效应用反射机制
Java反射是一种强大功能,允许程序在运行时动态获取类信息、创建对象、调用方法和访问字段,提升程序灵活性。它在框架开发、动态代理、注解处理等场景中广泛应用,如Spring和Hibernate。但反射也存在性能开销、安全风险和代码复杂性,应谨慎使用。
|
3月前
|
人工智能 Java
Java中的反射机制:深入探索与应用
本文介绍了Java反射机制的基本概念、用途及其实现方式。反射机制允许程序在运行时动态获取类的属性和方法,并调用它们,适用于处理私有成员或权限受限的情况。文章详细讲解了`Class`类的功能,包括获取类的方法、属性、注解、构造器等信息,以及通过四种方式获取`Class`对象的示例代码。此外,还探讨了类加载器、继承关系判断、动态代理等高级内容,展示了如何在运行时创建接口实例并处理方法调用。文末提供了完整的代码示例以加深理解。
Java中的反射机制:深入探索与应用
|
4月前
|
Java 区块链 网络架构
酷阿鲸森林农场:Java 区块链系统中的 P2P 区块同步与节点自动加入机制
本文介绍了基于 Java 的去中心化区块链电商系统设计与实现,重点探讨了 P2P 网络在酷阿鲸森林农场项目中的应用。通过节点自动发现、区块广播同步及链校验功能,系统实现了无需中心服务器的点对点网络架构。文章详细解析了核心代码逻辑,包括 P2P 服务端监听、客户端广播新区块及节点列表自动获取等环节,并提出了消息签名验证、WebSocket 替代 Socket 等优化方向。该系统不仅适用于农业电商,还可扩展至教育、物流等领域,构建可信数据链条。
|
4月前
|
人工智能 JavaScript Java
Java反射机制及原理
本文介绍了Java反射机制的基本概念、使用方法及其原理。反射在实际项目中比代理更常用,掌握它可以提升编程能力并理解框架设计原理。文章详细讲解了获取Class对象的四种方式:对象.getClass()、类.class、Class.forName()和类加载器.loadClass(),并分析了Class.forName()与ClassLoader的区别。此外,还探讨了通过Class对象进行实例化、获取方法和字段等操作的具体实现。最后从JVM类加载机制角度解析了Class对象的本质及其与类和实例的关系,帮助读者深入理解Java反射的工作原理。
103 0
|
6月前
|
缓存 Dubbo Java
理解的Java中SPI机制
本文深入解析了JDK提供的Java SPI(Service Provider Interface)机制,这是一种基于接口编程、策略模式与配置文件组合实现的动态加载机制,核心在于解耦。文章通过具体示例介绍了SPI的使用方法,包括定义接口、创建配置文件及加载实现类的过程,并分析了其原理与优缺点。SPI适用于框架扩展或替换场景,如JDBC驱动加载、SLF4J日志实现等,但存在加载效率低和线程安全问题。
276 7
理解的Java中SPI机制
|
5月前
|
存储 Java 编译器
Java 中 .length 的使用方法:深入理解 Java 数据结构中的长度获取机制
本文深入解析了 Java 中 `.length` 的使用方法及其在不同数据结构中的应用。对于数组,通过 `.length` 属性获取元素数量;字符串则使用 `.length()` 方法计算字符数;集合类如 `ArrayList` 采用 `.size()` 方法统计元素个数。此外,基本数据类型和包装类不支持长度属性。掌握这些区别,有助于开发者避免常见错误,提升代码质量。
466 1