【Java】反射与注解(一)反射

本文详细介绍了Java反射机制,包括其概念、优缺点、用途及如何使用反射技术来操作类、对象的属性和方法。通过反射,可以在运行时动态创建对象、调用方法,实现灵活的代码设计。同时,文中提到了反射在JDBC驱动加载、Spring框架中的应用,以及自定义注解的实现。然而,反射也会带来性能损耗和安全风险,应当谨慎使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 反射机制

1.1 什么是反射

Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.

The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control.

java反射机制的核心就是在程序运行时动态的获取类的信息, 进而控制类或对象的属性和方法 它的本质就是jvm在取得class对象之后进行反编译,从而获取类的各种信息

java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁

1.2 反射机制的优缺点

反射常用于第三方框架

1、优点:在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。

2、缺点:

(1)反射会消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射;

(2)反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。

目的:提供开发者能够更好封装框架实现扩展功能。

1.3 反射的用途

  1. 反编译:.class–>.java

  2. 通过反射机制访问java对象的属性,方法,构造方法等

  3. JDBC加载驱动连接 class.forname

Class.forName("com.mysql.jdbc.Driver"); // 动态加载mysql驱动
  1. Spring容器框架IOC实例化对象
<bean id="elementheat" class="com.elementheat.UserEntity"  />  
  1. 自定义注解生效(反射+Aop)

  2. 第三方核心的框架 mybatis orm

1.4 反射技术的使用

Class类 代表类的实体,在运行的Java应用程序中表示类和接口

Field类 代表类的成员变量(成员变量也称为类的属性)

Method类 代表类的方法

Constructor类 代表类的构造方法

1.getField、getMethod和getCostructor方法可以获得指定名字的域、方法和构造器。

2.getFields、getMethods和getCostructors方法可以获得类提供的public域、方法和构造器数组,其中包括超类的共有成员

3.getDeclatedFields、getDeclatedMethods和getDeclaredConstructors方法可以获得类中声明的全部域、方法和构造器,其中包括私有和受保护的成员,但不包括超类的成员

1.4.1 反射常用的Api

​ (1) Object–>getClass

​ (2) 任何数据类型(包括基本的数据类型)都有一个“静态”的class属性

​ (3)通过class类的静态方法:forName(String className)(最常用)

// 方法1
User user = new User();
Class userClass1 = user.getClass();
// 方法2
Class userClass2 = User.class;
// 方法3
Class userClass3 = Class.forName("com.example.demo.pojo.User")
//运行期间,一个类,只有一个Class对象产生
// userClass1==userClass2==userClass3
1.4.2 反射执行构造函数

无参构造函数

User userInstance = (User) userClass.newInstance();

有参构造函数

Constructor constructor = userClass.getConstructor(String.class, int.class);
User userInstance = (User) constructor.newInstance("test", 5);
1.4.3 反射执行给属性赋值

查看所有属性

Class<?> userClass = Class.forName("com.example.demo.pojo.User");
Field[] declaredFields = userClass.getDeclaredFields();
Arrays.stream(declaredFields).forEach((field -> System.out.println(field.getName())));

公有属性赋值

Class<?> userClass = Class.forName("com.example.demo.pojo.User");
User user = (User) userClass.newInstance();
Field usernameField = userClass.getField("username");
usernameField.set(user,"myName");
System.out.println(user);

私有属性赋值

Class<?> userClass = Class.forName("com.example.demo.pojo.User");
User user = (User) userClass.newInstance();
Field idField = userClass.getDeclaredField("id");
//允许访问私有属性
idField.setAccessible(true);
idField.set(user,"111");
System.out.println(user);
1.4.4 反射执行调用方法

查看所有方法

Class<?> userClass = Class.forName("com.example.demo.pojo.User");
Method[] declaredMethods = userClass.getDeclaredMethods();
Arrays.stream(declaredMethods).forEach(method -> System.out.println(method.getName()));

调用公有方法

Class<?> userClass = Class.forName("com.example.demo.pojo.User");
User user = (User) userClass.newInstance();
Method publicMethod = userClass.getMethod("publicMethod");
publicMethod.invoke(user);

调用私有方法

Class<?> userClass = Class.forName("com.example.demo.pojo.User");
User user = (User) userClass.newInstance();
Method privateMethod = userClass.getDeclaredMethod("privateMethod");
//允许调用私有方法
privateMethod.setAccessible(true);
privateMethod.invoke(user);

调用方法传递参数

Class<?> userClass = Class.forName("com.example.demo.pojo.User");
User user = (User) userClass.newInstance();
Method paramMethod = userClass.getDeclaredMethod("paramMethod", Integer.class, Integer.class);
Object invoke = paramMethod.invoke(user,1,2);
System.out.println(invoke);

通过反射越过泛型检查

ArrayList<String> strings = new ArrayList<>();
strings.add("test");
Class<? extends ArrayList> aClass = strings.getClass();
Method add = aClass.getDeclaredMethod("add", Object.class);
add.invoke(strings,5);
System.out.println(strings);
//foreach遍历时会报错 因为foreach限定了每个元素的类型, 无法强转Integer-String则报错
strings.forEach(s -> System.out.println(s));

泛型用在编译期,编译过后泛型擦除(消失掉),所以是可以通过反射越过泛型检查的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值