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. 简述简单工厂设计模式与动态工厂设计模式的区别?

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

相关推荐
等一场春雨20 分钟前
Java 23 集合框架详解:ArrayList、LinkedList、Vector
java·开发语言
Hello Dam22 分钟前
分布式环境下定时任务扫描时间段模板创建可预订时间段
java·定时任务·幂等性·redis管道·mysql流式查询
javaweiming22 分钟前
根据中文名称首字母进行分组
java·汉字转拼音
qincjun23 分钟前
Qt仿音乐播放器:媒体类
开发语言·qt
小白编程952726 分钟前
matlab离线安装硬件支持包
开发语言·matlab
桂月二二1 小时前
深入探索 Rust 中的异步编程:从基础到实际案例
开发语言·后端·rust
早上好啊! 树哥3 小时前
JavaScript Math(算数) 对象的用法详解
开发语言·javascript·ecmascript
noravinsc4 小时前
requests请求带cookie
开发语言·python·pycharm
水宝的滚动歌词6 小时前
设计模式之建造者模式
java·设计模式·建造者模式
孤蓬&听雨6 小时前
Java SpringBoot使用Apache POI导入导出Excel文件
java·spring boot·apache·excel导出·excel导入