如何在Java中实现具有同形方法的接口?
在英语中,同形异义词对是两个拼写相同但含义不同的单词。
在软件工程中,一对同源方法是名称相同但要求不同的两种方法。让我们看一个人为的例子,使问题尽可能清晰:
interface I1 {
/** return 1 */
int f()
}
interface I2 {
/** return 2*/
int f()
}
interface I12 extends I1, I2 {}
如何实现?C#有办法做到这一点,但Java没有。因此,唯一的解决方法是黑客攻击。如何最可靠地使用反射/字节码技巧/等来完成(即它不必是一个完美的解决方案,我只想要一个效果最好的解决方案)?I12
请注意,一些现有的闭源大量遗留代码,我无法合法地进行逆向工程,这需要一个类型的参数,并将两者都委托给作为参数的代码和作为参数的代码。因此,基本上我需要使一个实例知道它何时应该充当,何时应该充当 ,我相信这可以通过在直接调用方的运行时查看字节码来完成。我们可以假设调用方不使用反射,因为这是简单的代码。问题是的作者没想到Java从两个接口合并,所以现在我必须想出解决这个问题的最佳技巧。没有调用(显然,如果作者编写了一些实际调用的代码,他会在出售之前注意到这个问题)。I12
I12
I1
I2
I12
I1
I2
I12
f
I12.f
I12.f
请注意,我实际上是在寻找这个问题的答案,而不是如何重构我无法更改的代码。我正在寻找最好的启发式方法或确切的解决方案(如果存在的话)。请参阅Gray的答案以获取有效示例(我相信有更强大的解决方案)。
下面是一个具体的例子,说明两个接口中的同型方法问题是如何发生的。这是另一个具体的例子:
我有以下6个简单的类/接口。它类似于剧院周围的业务和在其中表演的艺术家。为了简单和具体,让我们假设它们都是由不同的人创建的。
Set
表示一个集合,如集合论中所示:
interface Set {
/** Complements this set,
i.e: all elements in the set are removed,
and all other elements in the universe are added. */
public void complement();
/** Remove an arbitrary element from the set */
public void remove();
public boolean empty();
}
HRDepartment
用于表示员工。它使用复杂的流程来解码要雇用/解雇哪些员工:Set
import java.util.Random;
class HRDepartment {
private Random random = new Random();
private Set employees;
public HRDepartment(Set employees) {
this.employees = employees;
}
public void doHiringAndLayingoffProcess() {
if (random.nextBoolean())
employees.complement();
else
employees.remove();
if (employees.empty())
employees.complement();
}
}
a的员工范围可能是向雇主申请的员工。因此,当在该集合上被调用时,所有现有员工都将被解雇,并且之前应用的所有其他员工都将被雇用。Set
complement
Artist
代表艺术家,例如音乐家或演员。艺术家有自我。当别人称赞他时,这种自我会增加:
interface Artist {
/** Complements the artist. Increases ego. */
public void complement();
public int getEgo();
}
Theater
进行表演,这可能会导致补充。剧院的观众可以在两场演出之间评判艺术家。表演者的自我越高,观众就越有可能喜欢,但如果自我超出了某个点,艺术家就会被观众负面地看待:Artist
Artist
Artist
import java.util.Random;
public class Theater {
private Artist artist;
private Random random = new Random();
public Theater(Artist artist) {
this.artist = artist;
}
public void perform() {
if (random.nextBoolean())
artist.complement();
}
public boolean judge() {
int ego = artist.getEgo();
if (ego > 10)
return false;
return (ego - random.nextInt(15) > 0);
}
}
ArtistSet
只是一个和一个:Artist
Set
/** A set of associated artists, e.g: a band. */
interface ArtistSet extends Set, Artist {
}
TheaterManager
运行节目。如果剧院的观众对艺术家的评价是负面的,剧院就会与人力资源部门交谈,人力资源部门反过来会解雇艺术家,雇用新艺术家等:
class TheaterManager {
private Theater theater;
private HRDepartment hr;
public TheaterManager(ArtistSet artists) {
this.theater = new Theater(artists);
this.hr = new HRDepartment(artists);
}
public void runShow() {
theater.perform();
if (!theater.judge()) {
hr.doHiringAndLayingoffProcess();
}
}
}
一旦你尝试实现一个:两个超接口都指定应该做其他事情,所以你必须以某种方式在同一类中实现两个具有相同签名的方法,问题就变得很明显了。 是 的同形异义词。ArtistSet
complement
complement
Artist.complement
Set.complement