讲师中心 微信公众号
AI工具推荐 视频效率加速

如何在抽象基类的 main 方法中动态实例化并调用具体子类

陌辰大大_6829

陌辰大大_6829

发布时间:2026-02-05 14:20:01

|

1207人浏览过

|

来源于php中文网

原创

如何在抽象基类的 main 方法中动态实例化并调用具体子类

本文介绍一种专业、可行的方式,让抽象基类 `calculation` 的 `main` 方法能自动发现并实例化所有继承它的具体子类(如 `mone`、`mtwo`),从而实现 `java mone 5` 等命令直接输出对应计算结果。核心在于运行时类路径扫描与反射实例化。

要实现在抽象基类 Calculation 的 main 方法中调用不同子类的 multiply() 方法,关键在于脱离“硬编码 new”,转而采用运行时动态发现 + 反射创建实例的策略。因为 main 方法位于抽象类中,它无法直接 new Calculation(),但可通过类路径扫描识别所有非抽象子类,并逐一实例化执行。

✅ 推荐方案:使用 ClassGraph 实现子类自动发现

ClassGraph 是一个高性能、轻量级的类路径扫描库,可安全、高效地枚举继承自指定基类的所有具体类(即非抽象、非接口的子类)。以下是完整可运行的改进版 Calculation 类:

import io.github.classgraph.ClassGraph;
import io.github.classgraph.ScanResult;

import java.util.List;

public abstract class Calculation {
    public abstract int multiply(int x);

    public static void main(String[] args) {
        if (args.length == 0) {
            System.err.println("Usage: java <Subclass> <number>");
            return;
        }

        try {
            // 解析输入参数(取第一个作为待计算数值)
            int input = Integer.parseInt(args[0]);

            // 扫描所有 Calculation 的具体子类
            List<Class<? extends Calculation>> subclasses;
            try (ScanResult scanResult = new ClassGraph()
                    .enableClassInfo()
                    .acceptPackages("your.package.name") // ? 替换为你的实际包名,提升性能与安全性
                    .scan()) {

                subclasses = scanResult
                        .getSubclasses(Calculation.class.getName())
                        .filter(classInfo -> !classInfo.isAbstract()) // 排除抽象子类(如有)
                        .loadClasses();
            }

            // 对每个具体子类实例化并调用 multiply
            for (Class<? extends Calculation> clazz : subclasses) {
                try {
                    Calculation instance = clazz.getDeclaredConstructor().newInstance();
                    int result = instance.multiply(input);
                    System.out.println(clazz.getSimpleName() + ": " + result);
                } catch (Exception e) {
                    System.err.println("Failed to instantiate or invoke " + clazz.getName() + ": " + e.getMessage());
                }
            }

        } catch (NumberFormatException e) {
            System.err.println("Invalid number argument: " + args[0]);
        }
    }
}
? 重要注意事项:✅ 子类(如 MOne)必须提供无参构造函数(默认即满足),否则 newInstance() 或 getDeclaredConstructor().newInstance() 会抛出异常;✅ 建议通过 .acceptPackages(...) 显式限定扫描范围,避免全类路径扫描带来的性能开销和潜在安全风险;✅ 若子类位于模块化环境(Java 9+),需确保 module-info.java 中 opens 相应包以支持反射访问;❌ 不推荐使用已弃用的 Class.newInstance()(Java 9+ 已标记为 deprecated),应统一使用 getDeclaredConstructor().newInstance()。

? 为什么不建议“在 main 中直接 new 子类”?

你可能会想到在 Calculation.main() 中写类似 new MOne().multiply(x) 的代码——但这违背了面向对象的开放封闭原则(OCP):每新增一个子类(如 MFour),就必须修改基类源码,丧失可扩展性。而上述 ClassGraph 方案实现了零侵入式扩展:只要新子类编译后在类路径中,且继承 Calculation,即可被自动识别并执行。

GitCode API Usage
GitCode API Usage

简单易用的 GitCode API SKILL,提供 CLI 和轻量级 Python SDK 两种调用方式,用于与 GitCode 的 REST API 进行交互。支持加密访问令牌、异步调用以及完善的类型提示。 - 文档:https://gitcode-api.readthedocs.io/ - PyPI 页面:https://pypi.org/project/gitcode-api - GitHub 仓库:https://github.com/Trenza1ore/GitCode-API

下载

✅ 验证方式(终端命令)

确保所有类(Calculation, MOne, MTwo, MThree)已编译,并在类路径中:

# 运行基类 main —— 它会自动发现并调用所有子类
java -cp ".:classgraph-4.8.167.jar" Calculation 5
# 输出示例:
# MOne: 5
# MTwo: 10
# MThree: 15

? 提示:若你坚持按 java MOne 5 方式启动(即子类各自拥有 main),则无需改动 Calculation;只需在每个子类中复用逻辑即可。但本文聚焦于单入口、多策略、自动发现这一更工程化的架构需求。

综上,通过 ClassGraph + 反射 + 显式包过滤,我们既保持了抽象基类的通用性,又赋予其智能化调度子类的能力——这是构建可插拔计算引擎、策略工厂或命令行工具链的坚实基础。

热门AI工具

更多
Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

AionClaw
AionClaw Hot

AionClaw是一款面向办公、创作和编程任务的AI桌面智能体。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

Seko
Seko Hot

一款AI视频创作工具,主要用于商汤科技推出的创编一体的AI短视频创作Agent,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

相关专题

更多
go语言 面向对象
go语言 面向对象

本专题整合了go语言面向对象相关内容,阅读专题下面的文章了解更多详细内容。

6655

2025.09.05

java面向对象
java面向对象

本专题整合了java面向对象相关内容,阅读专题下面的文章了解更多详细内容。

342

2025.11.27

C++ 面向对象编程与设计模式实践
C++ 面向对象编程与设计模式实践

本专题整合了 C++ 面向对象编程的核心机制,涵盖类的定义与访问控制、构造函数与析构函数、拷贝语义与移动语义、继承与虚函数多态、抽象类与接口、运算符重载、友元函数等关键知识点,同时结合单例模式、工厂模式、观察者模式、策略模式等常用设计模式的 C++ 实现,帮助开发者写出结构清晰、易于维护的面向对象代码。

344

2026.04.09

Java 面向对象与核心编程机制
Java 面向对象与核心编程机制

系统讲解 Java 面向对象编程的核心知识体系,涵盖类的定义与封装、构造方法与 this/super 关键字、继承与方法重写、多态与向上向下转型、抽象类与接口的区别与设计原则、异常处理机制(try-catch-finally / 自定义异常)、泛型的类型参数与通配符、集合框架(List/Set/Map)的使用与遍历方式,帮助开发者全面掌握 Java 程序设计的核心机制与面向对象思维。

223

2026.04.17

go语言 面向对象
go语言 面向对象

本专题整合了go语言面向对象相关内容,阅读专题下面的文章了解更多详细内容。

6655

2025.09.05

java面向对象
java面向对象

本专题整合了java面向对象相关内容,阅读专题下面的文章了解更多详细内容。

342

2025.11.27

C++ 面向对象编程与设计模式实践
C++ 面向对象编程与设计模式实践

本专题整合了 C++ 面向对象编程的核心机制,涵盖类的定义与访问控制、构造函数与析构函数、拷贝语义与移动语义、继承与虚函数多态、抽象类与接口、运算符重载、友元函数等关键知识点,同时结合单例模式、工厂模式、观察者模式、策略模式等常用设计模式的 C++ 实现,帮助开发者写出结构清晰、易于维护的面向对象代码。

344

2026.04.09

Java 面向对象与核心编程机制
Java 面向对象与核心编程机制

系统讲解 Java 面向对象编程的核心知识体系,涵盖类的定义与封装、构造方法与 this/super 关键字、继承与方法重写、多态与向上向下转型、抽象类与接口的区别与设计原则、异常处理机制(try-catch-finally / 自定义异常)、泛型的类型参数与通配符、集合框架(List/Set/Map)的使用与遍历方式,帮助开发者全面掌握 Java 程序设计的核心机制与面向对象思维。

223

2026.04.17

Gradle插件开发入门教程
Gradle插件开发入门教程

本专题介绍Gradle插件开发的基本流程,涵盖插件类编写、自定义任务注册、扩展参数设计和插件应用方法,帮助你理解插件如何组织构建逻辑,减少多个项目之间的重复配置。

0

2026.10.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn