Skip to content

Java Interop

Himxh edited this page Oct 4, 2026 · 1 revision

Java 互操作 / Java Interop

为什么要和 Java 交互 / Why Java Interop

HimDSL 运行在 Bukkit 服务端上,所有功能都是 Java 提供的。选择器、占位符、事件都已经封装好,绝大多数情况下你用不上 Java 互操作。但有些场景例外:

HimDSL runs on a Bukkit server — everything is Java underneath. Selectors, placeholders, and events are pre-wrapped; most of the time you never need Java interop. A few cases call for it:

  • 调用某个 Java 类的静态工具方法。

  • 引用 Java 提供的常量(如物品、生物群系、粒子)。

  • 创建 Bukkit 的对象(如 Location、ItemStack、Vector)。

  • Calling a static utility method on a Java class.

  • Referencing Java constants (items, biomes, particles).

  • Constructing Bukkit objects (Location, ItemStack, Vector).

本章覆盖这三种场景。

This chapter covers those three cases.


引用 Java 类 / Referring to Java Classes

用类名引用。全限定名和简单名都支持:

Reference by class name. Both fully-qualified and simple names work:

Material.DIAMOND                    // 简单名
org.bukkit.Material.DIAMOND         // 全限定名

简单名会在常见的包里查找(org.bukkit、org.bukkit.entity、org.bukkit.event.player 等)。如果找不到,需要写全限定名:

Simple names search common packages (org.bukkit, org.bukkit.entity, org.bukkit.event.player, etc.). If not found, use the fully-qualified name:

com.example.myplugin.MyClass.CONSTANT

简单名不用写包路径,读起来更干净。日常引用 Bukkit 类型优先用简单名。

Simple names skip the package and read cleaner. Prefer them for everyday Bukkit references.


引用静态字段 / Referencing Static Fields

Java 类的公开静态字段可以直接读:

Read public static fields on Java classes directly:

var stone = Material.STONE;
var creative = GameMode.CREATIVE;
var diamond = Material.DIAMOND_SWORD;

读取到的值就是 Java 对象本身,可以传进方法或用于比较。

The result is the Java object itself; you can pass it to methods or compare it.

if (player.gamemode == GameMode.CREATIVE) {
    runcmd("CONSOLE", "say 创造模式");
}

枚举常量就是静态字段的一种。上面 Material.STONE 和 GameMode.CREATIVE 都是枚举常量,写法与普通静态字段相同。

Enum constants are static fields. Both Material.STONE and GameMode.CREATIVE above are enum constants, written just like other static fields.


调用静态方法 / Calling Static Methods

用 类名.方法名(参数) 调用静态方法:

Call static methods with ClassName.method(args):

string name = Material.DIAMOND.name();
var all = Material.values();                // 全部 Material 常量
var sword = Material.valueOf("DIAMOND_SWORD");

Material.values() 返回一个列表,可以遍历:

Material.values() returns a list you can iterate:

var mats = Material.values();
int count = mats.size();
runcmd("CONSOLE", "say Material 常量数: " + count);

调用静态方法时参数类型要匹配。HimDSL 会尝试自动转换(int → long、字符串 → 枚举),但类型实在不匹配时会报"找不到匹配的静态方法"。

Argument types must match. HimDSL auto-converts where it can (int → long, string → enum), but truly incompatible types error with "no matching static method".


用 new 创建 Java 对象 / Creating Java Objects with new

new 关键字调用 Java 构造器:

The new keyword invokes a Java constructor:

var loc = new Location(world, 100.0, 64.0, 200.0);
var item = new ItemStack(Material.DIAMOND, 5);
var vec = new Vector(1.0, 0.0, 0.0);

new 接收的参数类型和个数必须与某个构造器匹配。HimDSL 会按参数尝试各构造器:

Arguments must match some constructor by type and count:

new ItemStack(Material.DIAMOND)             // 单个 Material
new ItemStack(Material.DIAMOND, 5)          // Material + 数量
new ItemStack(Material.DIAMOND, 5, true)    // 带 metadata

参数类型不对会报"找不到匹配的构造器"。检查参数顺序和类型是最常见的调试方式。

Wrong types error with "no matching constructor". Check argument order and types first when debugging.

例子:把玩家传送到坐标 / Example: Teleport a Player

int main() {
    var p = @p;
    var world = p.getWorld();
    var target = new Location(world, 100.0, 64.0, 200.0);

    p.teleport(target);
    runcmd("CONSOLE", "say 已传送 " + p.name);
}

p.getWorld() 和 p.teleport(...) 是通过 EntityRef 反射调用的 Java 方法。返回的 World 对象可以直接传给 new Location(...)。

p.getWorld() and p.teleport(...) go through EntityRef reflection. The returned World can be passed to new Location(...) directly.


枚举常量的两种写法 / Two Ways to Reference Enum Constants

Java 枚举常量可以两种写法:

Java enum constants support two forms:

// 通过 Java 类
var m = Material.DIAMOND;

// 通过字符串转(部分方法会这么做)
p.setGameMode("creative");

第二种依赖自动转换:方法期望枚举,HimDSL 会把字符串转成对应枚举。拼写要正确,否则报"参数类型不匹配"。

The second relies on auto-conversion: a method expecting an enum receives a string, which HimDSL converts. Spell it correctly, or "type mismatch" errors.

推荐用第一种。它是静态检查的,拼错会在引用时立刻报错。

Prefer the first form. It is statically checked; typos error immediately.


EntityRef 的自动包装 / Automatic EntityRef Wrapping

调用 Java 方法时,如果返回值是 Bukkit 的 Entity,HimDSL 会自动包成 EntityRef:

When Java methods return a Bukkit Entity, HimDSL auto-wraps it into an EntityRef:

var target = someMethodThatReturnsEntity();

// 得到的是 EntityRef,可以继续用字段式访问
string name = target.name;
double x = target.x;

这条规则让 Java 对象和 HimDSL 引用之间的衔接非常自然:大部分情况下你不需要关心底层类型是什么。

This rule makes Java and HimDSL blend smoothly: you rarely need to worry about the underlying type.


什么时候不用 Java 互操作 / When Not to Use Java Interop

HimDSL 已经封装了大部分常见操作。能用 HimDSL 语法的,就别深入 Java:

HimDSL wraps most common operations. If a HimDSL form exists, use it:

需求 推荐写法 不推荐
找玩家 @p、@a Bukkit.getOnlinePlayers()
玩家属性 p.name、p.health p.getName()、p.getHealth()
广播 runcmd("CONSOLE", "say ...") Bukkit.broadcastMessage(...)
发消息 p.sendMessage(...) runcmd(p.name, "msg ...")
定时任务 @BukkitRunnable Bukkit.getScheduler()
Need Prefer Avoid
Find players @p, @a Bukkit.getOnlinePlayers()
Player fields p.name, p.health p.getName(), p.getHealth()
Broadcast runcmd("CONSOLE", "say ...") Bukkit.broadcastMessage(...)
Send message p.sendMessage(...) runcmd(p.name, "msg ...")
Timer @BukkitRunnable Bukkit.getScheduler()

Java 互操作是"逃生舱",不是主路径。当你需要的东西 HimDSL 没有直接支持时,才动它。

Java interop is an escape hatch, not the main path. Reach for it when HimDSL has no direct form.


常见错误 / Common Mistakes

错误一:类名找不到

var x = MyRandomClass.FIELD;    // ✗ 找不到类

简单名只在默认包里找。不在其中的话用全限定名:

var x = com.example.MyRandomClass.FIELD;

错误二:new 的参数不匹配

var item = new ItemStack(5, Material.DIAMOND);      // ✗ 顺序错了

按官方文档写参数顺序。IDE 里按 Ctrl+Q(或平台对应键)可以看构造器签名。

错误三:把 new 用在结构体上

struct Point { int x; int y; };

var p = new Point();            // ✗

结构体用 Point p;。

Mistake 1: Class not found

Simple names search only default packages. Use a fully-qualified name.

Mistake 2: Wrong constructor arguments

Follow the official docs for parameter order.

Mistake 3: new on a struct

Structs use Point p;.


小结 / Summary

  • 引用 Java 类:简单名或全限定名。

  • 静态字段:ClassName.FIELD。

  • 静态方法:ClassName.method(args)。

  • 构造对象:new ClassName(args)。

  • 返回值是 Entity 时自动包成 EntityRef。

  • HimDSL 已有封装的操作优先用封装,Java 互操作是兜底。

  • Refer to Java classes by simple or fully-qualified name.

  • Static fields: ClassName.FIELD.

  • Static methods: ClassName.method(args).

  • Construct objects: new ClassName(args).

  • Returned Entity is auto-wrapped into EntityRef.

  • Prefer HimDSL's own forms; interop is a fallback.


自定义类型部分回顾 / Custom Types Review

自定义类型部分到此结束。四章覆盖了:结构体定义与字段、结构体方法、用户枚举、Java 互操作。

The Custom Types section ends here. Four chapters covered: struct definition and fields, struct methods, user enums, and Java interop.

选择原则:

Decision guide:

  • 一组相关数据 → struct。

  • 有限固定取值 → enum。

  • 与外部 Java 交互 → Java 互操作,但只在 HimDSL 没封装时使用。

  • A group of related values → struct.

  • A finite fixed set → enum.

  • Interop with external Java → interop, but only when HimDSL has no wrapped form.

默认用基本类型和容器,只有明确需要时才定义结构体或枚举。不要为了"看起来专业"而给简单数据加包装。

Default to primitives and containers; define structs or enums only when clearly needed. Do not add wrappers for simple data just to look professional.


下一步 / Next Steps

下一部分进入 Minecraft 集成。第十章 [选择器总览 / Selectors-Overview] 系统讲解选择器的所有形式与过滤规则。

The next part covers Minecraft Integration. Chapter [选择器总览 / Selectors-Overview] walks through all selector forms and filter rules.


HimDSL 文档 / Documentation

入门 / Getting Started

语言基础 / Language Basics

控制流 / Control Flow

函数 / Functions

数据结构 / Data Structures

自定义类型 / Custom Types

Minecraft 集成 / Minecraft Integration

事件与调度 / Events & Scheduling

GUI 系统 / GUI System

内置函数参考 / Built-ins Reference

进阶 / Advanced

扩展 API / Extension API

你真的需要 API 吗?/ Do you really need the API?

Clone this wiki locally