当前位置: 首页 > news >正文

第十七章 反射与设计模式

一、反射机制

1. 核心概念拆解

• 实例对象:通过new关键字创建的类实体,直接对应类的业务实例,包含成员变量、方法的具体数据。

• Class类对象:JVM在类加载时自动生成的“类元数据容器”,封装了类的全限定名、父类、接口、构造器、方法、字段等所有结构信息,是反射操作的核心入口。

• 反射:一种动态获取类信息、调用类成员的技术,打破了编译期的封装限制,允许程序在运行时操作类的结构,是框架实现灵活性的核心基础。
2. 获取Class对象的三种方式

1. 实例对象调用getClass():适用于已有实例对象的场景
Student stu = new Student();
Class<?> clazz1 = stu.getClass(); // 获取Student类的Class对象
2. 类名直接调用.class属性:编译期即可确定类型,无需实例化
Class<?> clazz2 = Student.class; // 直接通过类名获取Class对象
3. Class类静态方法forName():通过全限定类名字符串动态加载类,框架中最常用
Class<?> clazz3 = Class.forName("com.example.Student");
// 必须传入"包名.类名"格式的全限定名,否则抛出ClassNotFoundException
3. 类加载触发时机

• 首次创建类的实例(new关键字)

• 首次调用类的静态成员(静态变量、静态方法)

• 子类加载时,会优先触发父类的加载

• 调用Class.forName()获取Class对象时,直接触发类加载
4. 反射常用API详解

(1)获取类的基本信息
Class<?> clazz = Class.forName("com.example.Student");
String className = clazz.getName(); // 获取全限定类名:com.example.Student
String simpleName = clazz.getSimpleName(); // 获取简单类名:Student
Class<?> superClass = clazz.getSuperclass(); // 获取父类的Class对象
Class<?>[] interfaces = clazz.getInterfaces(); // 获取类实现的所有接口
(2)获取类的成员方法

• getMethods():获取本类及父类中所有public修饰的方法

• getDeclaredMethods():获取本类中所有方法(包括private、protected、default修饰的方法)
Method[] publicMethods = clazz.getMethods();
Method[] allMethods = clazz.getDeclaredMethods();
(3)通过反射创建实例对象

• 调用无参构造器创建实例(默认方式)
Class<?> clazz = Class.forName("com.example.Student");
Student student = (Student) clazz.newInstance(); // 底层调用无参构造器
注意:如果类没有无参构造器,会抛出InstantiationException。

• 调用有参构造器创建实例
// 1. 获取指定参数类型的构造器
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
// 2. 传入参数创建实例
Student student = (Student) constructor.newInstance("张三", 18);
(4)通过反射调用方法
// 1. 获取方法对象(方法名+参数类型)
Method studyMethod = clazz.getDeclaredMethod("study", String.class);
// 2. 解除私有方法的访问权限限制
studyMethod.setAccessible(true);
// 3. 调用方法(实例对象 + 方法参数)
studyMethod.invoke(student, "Java反射");
5. 反射的优缺点

• 优点:实现代码的动态性与通用性,是Spring、MyBatis等框架实现底层逻辑的核心技术,大幅提升程序的灵活性。

• 缺点:破坏类的封装性,可读性差;绕过编译期语法检查,错误只能在运行时暴露;性能低于直接调用,频繁反射会影响程序效率。
二、设计模式基础

1. 设计模式概述

设计模式是软件开发中反复出现问题的通用解决方案,是前人经验的总结,能提升代码的可复用性、可维护性和扩展性。Java中共有23种经典设计模式,本次重点学习单例模式与工厂模式。
2. 单例模式(Singleton Pattern)

单例模式确保一个类在JVM中只有一个实例对象,并提供全局访问入口,常用于配置类、连接池等场景。

(1)饿汉式单例
public class HungrySingleton {
// 类加载时直接创建实例
private static final HungrySingleton instance = new HungrySingleton();

// 私有构造器,禁止外部实例化
private HungrySingleton() {}

// 全局访问入口
public static HungrySingleton getInstance() {
return instance;
}
}
• 优点:实现简单,线程安全

• 缺点:类加载时就创建实例,占用内存,可能造成资源浪费

(2)懒汉式单例(线程安全版)
public class LazySingleton {
// 延迟初始化实例
private static LazySingleton instance;

private LazySingleton() {}

// 加锁保证线程安全
public static synchronized LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
• 优点:延迟加载,节省内存

• 缺点:加锁导致多线程环境下效率较低

(3)静态内部类单例(推荐写法)
public class InnerClassSingleton {
private InnerClassSingleton() {}

// 静态内部类,JVM加载时不会初始化
private static class SingletonHolder {
private static final InnerClassSingleton INSTANCE = new InnerClassSingleton();
}

public static InnerClassSingleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
• 优点:结合饿汉式与懒汉式的优点,线程安全且延迟加载,无性能损耗
3. 工厂模式(Factory Pattern)

工厂模式专门处理对象的创建逻辑,将对象创建与业务逻辑分离,提升代码的可维护性,结合反射可实现通用工厂。

(1)核心作用

将对象的创建逻辑封装在工厂类中,业务代码无需直接使用new创建对象,降低耦合度。

(2)结合反射的通用工厂实现
public class ObjectFactory {
// 根据全限定类名创建对象
public static Object createObject(String className) throws Exception {
Class<?> clazz = Class.forName(className);
return clazz.newInstance();
}
}
通过传入不同的全限定类名,即可创建不同类的实例,实现工厂的通用性。
4. Properties配置文件结合工厂模式

利用Properties读取配置文件,实现对象创建的解耦,是框架中常见的实现方式:
// 1. 创建Properties对象
Properties props = new Properties();
// 2. 加载配置文件
props.load(new FileInputStream("config.properties"));
// 3. 获取配置文件中的类全限定名
String className = props.getProperty("student.class");
// 4. 通过工厂创建对象
Student student = (Student) ObjectFactory.createObject(className);
• Properties是Hashtable的子类,默认键值对均为String类型

• load()方法可自动解析配置文件,按=或:分割键值对
💡 补充:反射破坏单例模式的问题

反射可以通过getConstructor()调用私有构造器,创建多个单例对象,破坏单例的唯一性。解决方案:在构造器中判断实例是否已存在,若存在则抛出异常:
private InnerClassSingleton() {
if (SingletonHolder.INSTANCE != null) {
throw new RuntimeException("单例模式不允许重复创建实例!");
}
}

http://www.rkmt.cn/news/1525333.html

相关文章:

  • 15分钟搞定Paperless-ngx多语言配置:从中文界面到全球文档管理的终极指南
  • 2026年6月工业吊扇厂家推荐,工业风扇/工业大吊扇/工业节能风扇/工业散热风扇/永磁工业风扇,工业吊扇产品哪个好 - 品牌推荐师
  • GoWxDump终极指南:跨平台微信数据提取与取证分析完整教程
  • 2026 济南奢侈品回收实测:添价收成本地靠谱变现优选 - 薛定谔的梨花猫
  • 终极指南:用Awesome-Dify-Workflow轻松构建专业级AI工作流 [特殊字符]
  • Linux命令-pinky(轻量级finger查询工具)
  • 罐头厂主要分布在哪里?产区特点有哪些差异?
  • AssetRipper完全指南:Unity游戏逆向分析与资源提取的终极解决方案
  • PowerQUICC II IMA微码实现:ATM反向复用的嵌入式软硬件协同设计
  • 2026武汉相亲机构实力盘点:合规甄选与高效脱单+正规交友渠道全指南 - 互联网科技品牌测评
  • 如何高效使用Qwerty Learner:本地词库存储与英语学习技术完全指南
  • 爱回收门店全程实测,估价和成交价到底差多少? - 新闻快传
  • Xbox手柄冲动触发器终极解锁:X1nput让PC游戏震动体验全面升级
  • 在爱回收卖手机,估价和到手价能差多少 - 新闻快传
  • 遗传算法实战精要:选择压力、适应度缩放与精英保留的工程化调优
  • 5大核心功能解密:dex2jar如何成为Android逆向工程必备神器
  • 3步掌握哔咔漫画下载器:打造个人专属漫画图书馆的完整攻略
  • 如何在macOS上获得终极歌词体验:LyricsX完整配置指南
  • 爱回收报价透明吗?三品类实测后聊聊我的判断 - 新闻快传
  • 【水下飞行器】基于matlab水下飞行器操控系统UVMS任务优先运动学控制与双重操作【含Matlab源码 15624期】
  • 洛雪音乐音源终极配置指南:5分钟快速搭建免费无损音乐库
  • Obsidian Dataview完整指南:3步将笔记库变为智能数据库
  • Vue + Axios 从入门到封装:拦截器、错误处理、请求取消、接口管理全搞定
  • APK-Installer:在Windows上安装安卓应用的终极完整指南
  • Android Studio中文界面终极指南:3分钟告别英文困扰的完整解决方案
  • 终极指南:如何让10美元鼠标在macOS上超越苹果触控板体验
  • Notepad--:跨平台文本编辑器的国产之光,打造高效开发新体验
  • 《鸿蒙原生应用开发实战》第二篇:ArkTS 数据模型与状态管理
  • (GR-RL)技术密档701-1000号摘要: 本技术文档集聚焦工业级具身智能系统的底层参数与核心算法,涵盖硬件控制、传感融合、运动规划及分布式训练等关键技术指标。主要内容包括:总线仲裁采用伺服驱动优
  • 5分钟从零制作专业视频:Auto-Video-Generator完全指南