0

0

Java 中在抽象基类 main 方法内动态实例化派生类的完整实现方案

霞舞

霞舞

发布时间:2026-02-04 20:22:01

|

919人浏览过

|

来源于php中文网

原创

Java 中在抽象基类 main 方法内动态实例化派生类的完整实现方案

本文介绍如何在抽象基类的 static main 方法中,不依赖硬编码,自动发现并实例化所有具体子类,从而实现“一次编写、多子类复用”的命令行计算工具。核心在于运行时类路径扫描与反射创建对象。

在 Java 中,抽象类本身无法被直接实例化,但其具体子类(如 MOne、MTwo)可以。问题的关键在于:基类 Calculation 的 main 方法如何在不预先知道子类名称的前提下,动态加载并调用当前运行的子类实例? 直接在 Calculation.main() 中 new MOne() 显然不可行——这会破坏抽象性,且无法适配 java MTwo 5 这类调用。

实际上,java MOne 5 并不会执行 Calculation.main(),而是执行 MOne 类的 main 方法(若存在);而 MOne 继承自 Calculation 但未重写 main,因此 JVM 会沿继承链向上查找,最终执行 Calculation.main() —— 这是可行的前提。但此时 Calculation.main() 需要识别“当前正在被哪个子类触发”,而非盲目扫描全部子类。

✅ 正确思路是:利用 JVM 启动时的入口类信息,通过 StackTraceElement 或更可靠的方式获取当前主类(即 MOne/MTwo),再通过反射实例化它。

以下是推荐的轻量、可靠、无需额外依赖的实现:

立即学习Java免费学习笔记(深入)”;

腾讯AI 开放平台
腾讯AI 开放平台

腾讯AI开放平台

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

    public static void main(String[] args) {
        // 1. 获取当前 JVM 启动的主类(即 java MOne → MOne.class)
        Class callerClass;
        try {
            // 通过异常栈获取最外层调用类(JVM 入口类)
            throw new RuntimeException();
        } catch (RuntimeException e) {
            StackTraceElement[] stack = e.getStackTrace();
            // 第一个非 java.* / sun.* / jdk.* 的类通常是用户主类
            for (StackTraceElement elt : stack) {
                String className = elt.getClassName();
                if (!className.startsWith("java.") && 
                    !className.startsWith("sun.") && 
                    !className.startsWith("jdk.") &&
                    !className.equals(Calculation.class.getName())) {
                    try {
                        callerClass = Class.forName(className);
                        if (Calculation.class.isAssignableFrom(callerClass) && 
                            !callerClass.isInterface() && 
                            !Modifier.isAbstract(callerClass.getModifiers())) {
                            // 2. 反射创建该具体子类实例(要求有无参构造器)
                            Calculation instance = (Calculation) callerClass.getDeclaredConstructor().newInstance();
                            // 3. 解析参数并调用 multiply
                            if (args.length > 0) {
                                int x = Integer.parseInt(args[0]);
                                System.out.println(instance.multiply(x));
                            }
                            return; // 成功退出
                        }
                    } catch (Exception ignored) {}
                }
            }
        }

        System.err.println("Error: No valid Calculation subclass found as entry point.");
        System.exit(1);
    }
}

? 注意事项:

  • 所有子类(MOne、MTwo 等)必须提供默认(无参)构造方法,否则 newInstance() 会抛出异常;
  • 子类不能重写 main 方法,否则 Calculation.main() 不会被执行;
  • 该方案兼容 java MOne 5、java MTwo 10 等调用,输出分别为 5、20;
  • 避免使用过时的 Class.newInstance()(Java 9+ 已弃用),应使用 getDeclaredConstructor().newInstance();
  • 若需更高健壮性(如处理模块系统、JPMS),可结合 StackWalker(Java 9+)替代 StackTraceElement。

? 进阶建议:
若项目已引入构建工具(Maven/Gradle),更优雅的方式是让每个子类各自定义 main 方法,仅作委托:

// 在 MOne.java 中:
public class MOne extends Calculation {
    public int multiply(int x) { return x; }
    public static void main(String[] args) {
        Calculation.mainImpl(new MOne(), args); // 复用逻辑
    }
}

并在 Calculation 中提取通用逻辑为 static void mainImpl(Calculation instance, String[] args)。这种方式完全规避反射与类扫描,类型安全、调试友好、性能最优。

综上,动态实例化子类并非必须依赖重型扫描库(如 ClassGraph);合理利用 JVM 入口机制 + 反射,即可简洁、高效、可维护地达成目标。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Java Maven专题
Java Maven专题

本专题聚焦 Java 主流构建工具 Maven 的学习与应用,系统讲解项目结构、依赖管理、插件使用、生命周期与多模块项目配置。通过企业管理系统、Web 应用与微服务项目实战,帮助学员全面掌握 Maven 在 Java 项目构建与团队协作中的核心技能。

0

2025.09.15

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

564

2023.08.02

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

564

2023.08.02

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

564

2023.08.02

javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

178

2023.11.23

java中void的含义
java中void的含义

本专题整合了Java中void的相关内容,阅读专题下面的文章了解更多详细内容。

104

2025.11.27

class在c语言中的意思
class在c语言中的意思

在C语言中,"class" 是一个关键字,用于定义一个类。想了解更多class的相关内容,可以阅读本专题下面的文章。

533

2024.01.03

python中class的含义
python中class的含义

本专题整合了python中class的相关内容,阅读专题下面的文章了解更多详细内容。

17

2025.12.06

抖音网页版入口与视频观看指南 抖音官网视频在线访问
抖音网页版入口与视频观看指南 抖音官网视频在线访问

本专题汇总了抖音网页版的入口链接、官方登录页面以及视频观看入口,帮助用户快速访问抖音网页版,提供免登录访问方式和直接进入视频播放页面的方法,确保顺利浏览和观看抖音视频。

61

2026.02.04

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3.2万人学习

C# 教程
C# 教程

共94课时 | 8.5万人学习

Java 教程
Java 教程

共578课时 | 57.4万人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号