You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spigot插件开发:如何将Shape实现类类型作为Selection构造方法参数?

嘿,这个问题我熟!你的思路其实是对的,用Class<? extends Shape>作为构造参数完全可行,不过具体实现的时候要注意反射的细节,另外还有更类型安全的替代方案,我给你一步步讲清楚:

方案一:使用Class类型参数(反射方式)

这种方式和你最初的想法一致,通过传入Shape实现类的Class对象,在Selection构造方法里利用反射创建对应的形状实例。

首先是Selection类的实现:

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Selection {
    private final int x;
    private final int z;
    private final int width;
    private final int depth;
    private final Shape shapeInstance;

    // 构造方法接收形状类型和区域参数
    public Selection(Class<? extends Shape> shapeType, int x, int z, int width, int depth) {
        this.x = x;
        this.z = z;
        this.width = width;
        this.depth = depth;

        try {
            // 假设你的Shape实现类都有接收x,z,width,depth的构造方法
            Constructor<? extends Shape> constructor = shapeType.getConstructor(int.class, int.class, int.class, int.class);
            this.shapeInstance = constructor.newInstance(x, z, width, depth);
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("形状类 " + shapeType.getName() + " 没有匹配的构造方法", e);
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException("创建形状实例失败", e);
        }
    }

    // 后续可以直接使用shapeInstance进行操作
    public void fillRegion() {
        // 调用Shape接口定义的方法,比如shapeInstance.fillBlocks();
    }
}

调用的时候就像这样:

// 创建矩形区域的Selection
Selection rectangleSelection = new Selection(Rectangle.class, 100, 200, 50, 30);
// 创建椭圆区域的Selection
Selection ellipseSelection = new Selection(Ellipse.class, 150, 250, 40, 60);

注意事项:

  • 必须保证所有Shape的实现类都有public的、参数为int, int, int, int的构造方法,否则反射会抛出异常。
  • 反射虽然灵活,但编译时无法检查构造方法是否存在,所以如果后续修改了Shape实现类的构造,需要同步更新Selection的反射逻辑。
方案二:使用Supplier(类型安全方案)

如果你想避免反射的潜在问题,更推荐用Supplier<Shape>或者函数式接口来传递形状的创建逻辑,这样编译时就能检查错误,类型更安全。

修改后的Selection类:

import java.util.function.Supplier;

public class Selection {
    private final int x;
    private final int z;
    private final int width;
    private final int depth;
    private final Shape shapeInstance;

    // 构造方法接收Supplier,让调用者负责创建形状实例
    public Selection(int x, int z, int width, int depth, Supplier<Shape> shapeSupplier) {
        this.x = x;
        this.z = z;
        this.width = width;
        this.depth = depth;
        this.shapeInstance = shapeSupplier.get();
    }
}

调用的时候可以用Lambda表达式或者方法引用,非常灵活:

// 用Lambda创建矩形
Selection rectangleSelection = new Selection(100, 200, 50, 30, 
    () -> new Rectangle(100, 200, 50, 30));

// 椭圆同理
Selection ellipseSelection = new Selection(150, 250, 40, 60, 
    () -> new Ellipse(150, 250, 40, 60));

优势:

  • 编译时就能检查形状实例的创建是否正确,不会出现反射的运行时异常。
  • 更灵活:如果某个Shape实现类需要特殊的构造参数,调用者可以自行处理,不需要修改Selection类的逻辑。
额外建议

如果你的Selection后续需要多次创建形状实例(而不是只创建一次),可以把Supplier<Shape>或者Class<? extends Shape>保存为成员变量,每次需要的时候再创建实例,而不是在构造方法里只创建一次。

比如修改方案一,保存Class对象:

public class Selection {
    private final Class<? extends Shape> shapeType;
    private final int x;
    private final int z;
    private final int width;
    private final int depth;

    public Selection(Class<? extends Shape> shapeType, int x, int z, int width, int depth) {
        this.shapeType = shapeType;
        this.x = x;
        this.z = z;
        this.width = width;
        this.depth = depth;
    }

    // 每次需要时创建实例
    public Shape createShapeInstance() {
        try {
            Constructor<? extends Shape> constructor = shapeType.getConstructor(int.class, int.class, int.class, int.class);
            return constructor.newInstance(x, z, width, depth);
        } catch (Exception e) {
            throw new RuntimeException("创建形状失败", e);
        }
    }
}

这样就可以根据需要多次创建形状对象啦!

内容的提问来源于stack exchange,提问作者DddoubleChin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:06:41