Java如何将变量的参数化类型设置为其所属类的类型
解决方案
Java 语法本身不支持伪代码中MyBotCommand<this>形式的自类型声明,但可以通过两种成熟方案实现你要的效果,完全消除业务代码中重复的强转逻辑。
方案1:递归泛型边界实现自类型绑定(完全匹配你的设计预期)
这是Java生态实现自类型的标准惯用法,通过递归泛型参数让父类自动持有子类的类型信息,只需要在基类做一次安全的类型转换,所有业务代码无需再写强转。
第一步:改造基类MyBotCommandFeature
给基类加递归泛型参数,同时封装内部的类型安全调用逻辑,解决通配符场景下的编译报错:
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.CheckForNull; import org.jetbrains.annotations.CheckReturnValue; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.HashSet; import java.util.Set; import java.util.stream.Stream; import static java.util.stream.Collectors.toSet; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; // F 代表子类自身的类型,递归边界约束F必须是当前基类的子类 public abstract class MyBotCommandFeature<F extends MyBotCommandFeature<F>> extends MyBotFeature { @NotNull public final Set<MyBotCommand<F>> commands; @SafeVarargs public MyBotCommandFeature(@NotNull MyBotCommand<F> @NotNull ... commands) { // 可选:加一层校验,防止子类写错泛型参数 Type superClass = this.getClass().getGenericSuperclass(); if (superClass instanceof ParameterizedType pt) { Type typeArg = pt.getActualTypeArguments()[0]; if (typeArg instanceof Class<?> c && !c.isInstance(this)) { throw new IllegalArgumentException("泛型参数必须传入当前Feature自身类型"); } } if (commands.length == 0) { this.commands = new HashSet<>(); } else { this.commands = Stream.of(commands).collect(toSet()); } } @Nullable @CheckForNull @CheckReturnValue public Set<MyBotCommand<F>> getExtraCommands(@NotNull Guild guild) { return null; } // 封装斜杠命令执行逻辑,仅在此处做一次安全的强转 @SuppressWarnings("unchecked") public final void execSlashCommand(@NotNull MyBotCommand<?> command, @NotNull SlashCommandInteractionEvent event) { // 强转100%安全:只有匹配当前F类型的命令才会被存入commands集合 ((MyBotCommand<F>) command).runSlashCommand(event, (F) this); } // 封装文本命令执行逻辑,同理 @SuppressWarnings("unchecked") public final void execTextCommand(@NotNull MyBotCommand<?> command, @NotNull MessageReceivedEvent event) { ((MyBotCommand<F>) command).runTextCommand(event, (F) this); } }
第二步:子类实现
子类继承时把自身类型作为泛型参数传入即可,命令实现中直接拿到对应子类类型的feature参数,无需强转:
public final class ExampleFeature extends MyBotCommandFeature<ExampleFeature> { public ExampleFeature() { super(new MyBotCommand<ExampleFeature>() { @Override public void runTextCommand(@NotNull MessageReceivedEvent event, @NotNull ExampleFeature feature) { // 直接调用子类专属方法,无强转 feature.customTextLogic(); } @Override public void runSlashCommand(@NotNull SlashCommandInteractionEvent event, @NotNull ExampleFeature feature) { feature.customSlashLogic(); } }); } // 子类专属方法 public void customTextLogic() { // 业务逻辑 } public void customSlashLogic() { // 业务逻辑 } }
第三步:改造事件监听逻辑
直接调用基类封装好的执行方法即可,无需处理类型转换:
@Override public void onSlashCommandInteraction(@NotNull SlashCommandInteractionEvent event) { for (MyBotCommandFeature<?> feature : features) { // 遍历内置命令 for (MyBotCommand<?> command : feature.commands) { if (command.name.equals(event.getName())) { feature.execSlashCommand(command, event); return; } } // 遍历额外命令 Set<MyBotCommand<?>> extraCommands = feature.getExtraCommands(event.getGuild()); if (extraCommands != null) { for (MyBotCommand<?> command : extraCommands) { if (command.name.equals(event.getName())) { feature.execSlashCommand(command, event); return; } } } } }
方案2:构造期绑定Feature实例(实现更简单)
如果觉得递归泛型太绕,可以直接改MyBotCommand的设计,在命令实例初始化的时候就绑定所属的Feature实例,完全不需要在执行方法上传参:
public abstract class MyBotCommand<F extends MyBotCommandFeature<?>> { // 初始化时就绑定所属Feature,子类直接访问 protected final F feature; protected MyBotCommand(F feature) { this.feature = feature; } // 执行方法不再需要传feature参数 public abstract void runTextCommand(@NotNull MessageReceivedEvent event); public abstract void runSlashCommand(@NotNull SlashCommandInteractionEvent event); }
子类实现时直接把this传给命令构造器:
public final class ExampleFeature extends MyBotCommandFeature { public ExampleFeature() { super(new MyBotCommand<ExampleFeature>(this) { @Override public void runTextCommand(@NotNull MessageReceivedEvent event) { // 直接访问成员变量feature,类型就是ExampleFeature,无强转 feature.customTextLogic(); } @Override public void runSlashCommand(@NotNull SlashCommandInteractionEvent event) { feature.customSlashLogic(); } }); } // 子类专属方法省略 }
事件监听逻辑直接调用无参的run方法即可,比泛型方案更简洁,唯一要求是构造命令时必须传入当前Feature的this实例。
内容的提问来源于stack exchange,提问作者hopperelec
相关产品推荐
相关产品推荐

