java实验4 反射机制

要求:

1)严禁上网抄袭、互相抄袭和各种形式的抄袭(如代码抄袭,运行截图一图多用),一旦发现单次作业按零分处理!

2)课程报告正文内容基本格式为:宋体,小五号,1.5 倍行距。

3)作业报告请务必保持排版的整洁规范,排版混乱者将直接判为不及格。

4)为避免办公软件兼容性导致的显示差异问题,要求在提交课程报告 WORD 文件的同

时提交相应的 PDF 版本。

一、实验目的

  1. 掌握通过反射动态加载类、创建实例、访问和修改对象的私有字段、调用对象的方法等操作。

  2. 掌握如何通过反射获取注解的操作。

  3. 掌握反射与设计模式的使用。

  • 实验内容

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| public class Student { private String name; private int age; public Student() { this.name = "Unknown"; this.age = 0; } public Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } public void displayInfo() { System.out.println("Name: " + name + ", Age: " + age); } private void privateMethod() { System.out.println("Private method called"); } } |

  1. 使用反射对类进行相关的操作。创建一个简单类 Student包含私有字段 name 和 age。包含一个无参构造方法和一个带参构造方法。包含公共方法 getName()、getAge() 和 displayInfo()。包含一个私有方法 privateMethod()。

  2. 使用反射机制动态加载 Student 类。

  3. 使用反射机制创建 Student 类的实例。

  4. 使用反射机制访问和修改 Student 类的私有字段。

  5. 使用反射机制调用 Student 类的公共方法和私有方法。

代码:

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

public class ReflectionExample {

public static void main(String[] args) {

try {

// 动态加载Student类

Class<?> studentClass = Class.forName("Student");

// 使用无参构造函数创建Student实例

Student student1 = (Student) studentClass.getDeclaredConstructor().newInstance();

// 使用带参构造函数创建Student实例

Constructor<?> constructor = studentClass.getDeclaredConstructor(String.class, int.class);

Student student2 = (Student) constructor.newInstance("晓晓", 25);

// 访问和修改私有字段

Field nameField = studentClass.getDeclaredField("name");

nameField.setAccessible(true);

nameField.set(student2, "晓晓");

Field ageField = studentClass.getDeclaredField("age");

ageField.setAccessible(true);

ageField.setInt(student2, 20);

// 调用公共方法

Method displayInfoMethod = studentClass.getMethod("displayInfo");

displayInfoMethod.invoke(student2);

// 调用私有方法

Method privateMethod = studentClass.getDeclaredMethod("privateMethod");

privateMethod.setAccessible(true);

privateMethod.invoke(student2);

} catch (Exception e) {

e.printStackTrace();

}

}

}

运行截图:

  1. 有如下场景:项目的持久化层需要使用到的数据库有Redis、MySql、MongoDB。

要求:

  1. 定义一个DataService接口,接口提供add()、delete()、update()、find()四个接口,对应各种数据库的增删改查操作。
  2. 分别实现RedisDataService、MySqlDataService、MongoDBDataService。
  3. 通过反射机制,实现动态工厂模式
  4. 从配置文件中读取需要使用的数据库名称,如redis对应"RedisDataService"、MySql对应"MySqlDataService"、MongoDB对应"MySqlDataService"
  5. 实例化配置文件中所配置的数据库服务对象

其中项目的数据库至少需要选择一种,可选择多种;

配置文件格式如下,则代表项目需要两种类型的数据库,需要创建两个实例。

|--------------------------------------------------|
| MySql:MySqlDataService MongoDB: MySqlDataService |

代码:

public interface DataService {

void add();

void delete();

void update();

void find();

}

public class RedisDataService implements DataService {

public void add() { System.out.println("Adding via Redis"); }

public void delete() { System.out.println("Deleting via Redis"); }

public void update() { System.out.println("Updating via Redis"); }

public void find() { System.out.println("Finding via Redis"); }

}

public class MySqlDataService implements DataService {

public void add() { System.out.println("Adding via MySQL"); }

public void delete() { System.out.println("Deleting via MySQL"); }

public void update() { System.out.println("Updating via MySQL"); }

public void find() { System.out.println("Finding via MySQL"); }

}

public class MongoDBDataService implements DataService {

public void add() { System.out.println("Adding via MongoDB"); }

public void delete() { System.out.println("Deleting via MongoDB"); }

public void update() { System.out.println("Updating via MongoDB"); }

public void find() { System.out.println("Finding via MongoDB"); }

}

import java.util.Properties;

public class DataServiceFactory {

public static DataService getDataService(String serviceName) {

try {

Class<?> clazz = Class.forName(serviceName);

return (DataService) clazz.getDeclaredConstructor().newInstance();

} catch (Exception e) {

e.printStackTrace();

return null;

}

}

}

MySql=MySqlDataService

MongoDB=MongoDBDataService

import java.io.FileInputStream;

import java.util.Properties;

public class Application {

public static void main(String[] args) {

try {

Properties properties = new Properties();

properties.load(new FileInputStream("config.properties"));

for (String key : properties.stringPropertyNames()) {

String className = properties.getProperty(key);

DataService service = DataServiceFactory.getDataService(className);

if (service != null) {

service.add();

service.delete();

service.update();

service.find();

}

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

运行截图:

  1. 通过反射和注解,自动生成接口文档。

|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| public class UserController { public static class UserDTO { @ApiModelProperty("用户id") Integer userId; @ApiModelProperty("用户名称") String name ; } public static class UserVO { @ApiModelProperty("用户id") Integer userId; @ApiModelProperty("用户名称") String name; @ApiModelProperty("手机号") String phone; } @PostMapping("/get_user") public UserVO conf(UserDTO dto) { return new UserVO(); } } @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ApiModelProperty { // 字段的注释 public String value() default ""; } |

要求:

  1. 实现自定义注解ApiModelProperty,用于字段描述。
  2. 实现自定义注解PostMapping,用于注明请求方法。
  3. UserDTO代表请求参数,UserVO对应响应参数。
  4. 使用反射机制获取注解信息,并生成一个接口文档,格式如下:

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 地址: http://localhost:8080/get_user 方法: post 请求参数: 字段名 类型 注释 userId integer 用户id name string 用户名称 返回参数: 字段名 类型 注释 userId integer 用户id Name string 用户名称 phone string 用户名称 |

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface ApiModelProperty {

String value() default "";

}

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface PostMapping {

String value() default "";

}

import java.lang.reflect.Field;

import java.lang.reflect.Method;

public class ApiDocumentationGenerator {

public static void generateDocumentation(Class<?> controllerClass) {

Method[] methods = controllerClass.getDeclaredMethods();

for (Method method : methods) {

if (method.isAnnotationPresent(PostMapping.class)) {

PostMapping postMapping = method.getAnnotation(PostMapping.class);

System.out.println("地址: http://localhost:8080" + postMapping.value());

System.out.println("方法: post");

Class<?>[] parameterTypes = method.getParameterTypes();

if (parameterTypes.length > 0) {

System.out.println("请求参数:");

System.out.println(" 字段名 类型 注释");

printFields(parameterTypes[0]);

}

Class<?> returnType = method.getReturnType();

System.out.println("返回参数:");

System.out.println(" 字段名 类型 注释");

printFields(returnType);

}

}

}

private static void printFields(Class<?> clazz) {

Field[] fields = clazz.getDeclaredFields();

for (Field field : fields) {

ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);

if (apiModelProperty != null) {

System.out.println(" " + field.getName() + " " + field.getType().getSimpleName().toLowerCase() + " " + apiModelProperty.value());

}

}

}

public static void main(String[] args) {

generateDocumentation(UserController.class);

}

}

三、思考题

  1. 反射机制实现动态代理的原理是什么?

++++反射机制实现动态代理的原理是在运行时创建代理类和对象,通过代理对象拦截对真实对象方法的调用,并允许在调用前后执行特定操作。这是通过 `java.lang.reflect.Proxy` 类和 `InvocationHandler` 接口实现的。++++

  1. 简述简单工厂设计模式与动态工厂设计模式的区别?

++++简单工厂设计模式是创建型模式,通过一个工厂类来创建不同类型的对象,客户端与具体产品解耦。动态工厂设计模式是简单工厂的扩展,它使用一个工厂方法来创建对象,允许在运行时动态决定创建何种产品。简单工厂在添加新产品时需要修改工厂类,而动态工厂通过继承或接口实现避免了这一点。++++

相关推荐
程序员的世界你不懂1 小时前
【Flask】测试平台开发,新增说明书编写和展示功能 第二十三篇
java·前端·数据库
星空寻流年1 小时前
设计模式第一章(建造者模式)
java·设计模式·建造者模式
lingchen19061 小时前
MATLAB的数值计算(三)曲线拟合与插值
开发语言·matlab
gb42152872 小时前
java中将租户ID包装为JSQLParser的StringValue表达式对象,JSQLParser指的是?
java·开发语言·python
一朵梨花压海棠go2 小时前
html+js实现表格本地筛选
开发语言·javascript·html·ecmascript
曾经的三心草2 小时前
Python2-工具安装使用-anaconda-jupyter-PyCharm-Matplotlib
android·java·服务器
蒋星熠2 小时前
Flutter跨平台工程实践与原理透视:从渲染引擎到高质产物
开发语言·python·算法·flutter·设计模式·性能优化·硬件工程
Metaphor6922 小时前
Java 高效处理 Word 文档:查找并替换文本的全面指南
java·经验分享·word
ChinaRainbowSea2 小时前
7. LangChain4j + 记忆缓存详细说明
java·数据库·redis·后端·缓存·langchain·ai编程
stormsha2 小时前
飞算JavaAI炫技赛电商系统商品管理模块的架构设计与实现
java·架构·鸿蒙系统