7

syntheticJava 在称为和的方法上有特殊标记bridge

JLS 13.1.7,“Java 编译器引入的任何在源代码中没有相应构造的构造都必须标记为合成……”

因此,合成方法是由编译器生成的任何东西,而不是在源代码中表示的东西,尽管该规范 PDF 中没有很好地提及它,但桥接方法用于类型检查泛型。(例如Animal.interactWith(Creature c),获得一个桥接方法interactWith(Object c),该方法转换为 Creature 并调用另一个方法。)


我们有一个名为 Bukkit 的 API,它提供了稳定的访问来改变 Minecraft 服务器的工作方式。API 底层实现的一个方面(又名 vanilla Minecraft),我们几乎无法控制,最近在版本中被迫1.6.1从整数值更改为浮点值。并且为了避免再次更改的困难,我们选择将我们所有的 API 方法更改为doubles.

因此,例如:

public int getHealth();
public void setHealth(int health);
// Must now be
public double getHealth();
public void setHealth(double health);

但是,与往常一样,我们希望使用以前版本编译的插件1.5.2,仍然尽可能地工作——这就是 API 的全部意义所在。

setHealth是一个已解决的问题,只需引入一个重载。目前,我们有一个名为的方法,它在实现编译(而不是API 编译)时_INVALID_getHealth(V)I被重命名为,这让旧插件继续运行。getHealth(V)I

然而,当有人试图扩展我们对这些重命名方法的实现时,他们会从双重命名的方法和覆盖中得到编译错误。

有没有办法使用手动/工具插入的合成或桥接方法同时提供int和返回,这不会导致那些试图更改我们 API 实现部分的人编译错误?double

4

2 回答 2

2

答案是肯定的——如果你将一个方法标记为不同的返回类型但与合成和桥接的参数相同,你可以编译子类。

在这种特定情况下,创建了一个新的 Maven 实用程序“Overmapper”来执行此任务,尽管您可以在任何可以编辑 Java 字节码的自动化工具中完成它。这是配置文件:

members:
  "org/bukkit/entity/Damageable _INVALID_damage (I)V": damage
  "org/bukkit/entity/Damageable _INVALID_damage (ILorg/bukkit/entity/Entity;)V": damage
  "org/bukkit/entity/Damageable _INVALID_getHealth ()I": getHealth
  "org/bukkit/entity/Damageable _INVALID_setHealth (I)V": setHealth
  "org/bukkit/entity/Damageable _INVALID_getMaxHealth ()I": getMaxHealth
  "org/bukkit/entity/Damageable _INVALID_setMaxHealth (I)V": setMaxHealth
  "org/bukkit/entity/LivingEntity _INVALID_getLastDamage ()I": getLastDamage
  "org/bukkit/entity/LivingEntity _INVALID_setLastDamage (I)V": setLastDamage
  "org/bukkit/event/entity/EntityDamageEvent _INVALID_getDamage ()I": getDamage
  "org/bukkit/event/entity/EntityDamageEvent _INVALID_setDamage (I)V": setDamage
  "org/bukkit/event/vehicle/VehicleDamageEvent _INVALID_getDamage ()I": getDamage
  "org/bukkit/event/vehicle/VehicleDamageEvent _INVALID_setDamage (I)V": setDamage
  "org/bukkit/event/entity/EntityRegainHealthEvent _INVALID_getAmount ()I": getAmount
  "org/bukkit/event/entity/EntityRegainHealthEvent _INVALID_setAmount (I)V": setAmount
  "org/bukkit/entity/Minecart _INVALID_getDamage ()I": getDamage
  "org/bukkit/entity/Minecart _INVALID_setDamage (I)V": setDamage
  "org/bukkit/entity/Projectile _INVALID_getShooter ()Lorg/bukkit/entity/LivingEntity;": getShooter
  "org/bukkit/entity/Projectile _INVALID_setShooter (Lorg/bukkit/entity/LivingEntity;)V": setShooter
  "org/bukkit/Bukkit _INVALID_getOnlinePlayers ()[Lorg/bukkit/entity/Player;": getOnlinePlayers
  "org/bukkit/Server _INVALID_getOnlinePlayers ()[Lorg/bukkit/entity/Player;": getOnlinePlayers
flags:
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftLivingEntity getHealth ()I": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftEnderDragonPart getHealth ()I": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftLivingEntity getMaxHealth ()I": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftEnderDragonPart getMaxHealth ()I": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftLivingEntity setHealth (I)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftEnderDragonPart setHealth (I)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftLivingEntity setMaxHealth (I)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftEnderDragonPart setMaxHealth (I)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftLivingEntity damage (I)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftEnderDragonPart damage (I)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftLivingEntity damage (ILorg/bukkit/entity/Entity;)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftEnderDragonPart damage (ILorg/bukkit/entity/Entity;)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftLivingEntity getLastDamage ()I": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftLivingEntity setLastDamage (I)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftMinecart setDamage (I)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftMinecart getDamage ()I": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftProjectile getShooter ()Lorg/bukkit/entity/LivingEntity;": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftProjectile setShooter (Lorg/bukkit/entity/LivingEntity;)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftArrow getShooter ()Lorg/bukkit/entity/LivingEntity;": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftArrow setShooter (Lorg/bukkit/entity/LivingEntity;)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftFireball getShooter ()Lorg/bukkit/entity/LivingEntity;": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftFireball setShooter (Lorg/bukkit/entity/LivingEntity;)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftFish getShooter ()Lorg/bukkit/entity/LivingEntity;": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftFish setShooter (Lorg/bukkit/entity/LivingEntity;)V": 0x1001

您可以看到所有返回 int 的方法都被更改为标记为桥接和合成。

于 2014-07-30T18:22:20.153 回答
-1

如果您想对实体健康做一些事情,您可以将其转换为 a Damageable,然后就不会再出现编译错误了。

Entity e = /* some entity */;
double health = ((Damageable) e).getHealth();

这应该有效。我希望它有帮助

于 2013-07-16T10:39:35.653 回答