使用通用父类型输入参数强制执行动态多态调用
我正在尝试使用多态性来根据对象的类启用对对象的不同处理,如下所示:
public class GeneralStuff {
private int ID;
}
public class IntStuff extends GeneralStuff {
private int value;
public void setValue(int v)
{
value = v;
}
public int getValue()
{
return value;
}
}
public class DoubleStuff extends GeneralStuff {
private double value;
public void setValue(double v)
{
value = v;
}
public double getValue()
{
return value;
}
}
public class ProcessStuff {
public String process(GeneralStuff gS)
{
return doProcess(gS);
}
private String doProcess(IntStuff i)
{
return String.format("%d", i.getValue());
}
private String doProcess(DoubleStuff d)
{
return String.format("%f", d.getValue());
}
}
public class Test {
public static void main(String[] args)
{
IntStuff iS = new IntStuff();
DoubleStuff dS = new DoubleStuff();
ProcessStuff pS = new ProcessStuff();
iS.setValue(5);
dS.setValue(23.2);
System.out.println(pS.process(iS));
System.out.println(pS.process(dS));
}
}
但是,这不起作用,因为调用 doProcess(gS)
需要一个带有签名 <代码>doProcess(GeneralStuff gS)。
我知道我可以在 ProcessStuff 类中只拥有两个公开的多态处理方法,但实际情况不允许这样做,因为我正在现有库机制的约束下工作;这只是一个为了测试而设计的示例。
当然,我可以将 process(GeneralStuff gS) 定义为
public String process(GeneralStuff gS)
{
if (gS instanceof IntStuff)
{
return doProcess((IntStuff) gS);
}
else if (gS instanceof DoubleStuff)
{
return doProcess((DoubleStuff) gS);
}
return "";
}
有效的,但似乎我不必这样做(另外,编程警察会因为我以这种方式使用 instanceof 而对我进行攻击) )。
有没有一种方法可以更好地强制执行多态调用?
预先感谢您的任何帮助。
I am trying to use polymorphism to enable different processing of an object based on its class, as follows:
public class GeneralStuff {
private int ID;
}
public class IntStuff extends GeneralStuff {
private int value;
public void setValue(int v)
{
value = v;
}
public int getValue()
{
return value;
}
}
public class DoubleStuff extends GeneralStuff {
private double value;
public void setValue(double v)
{
value = v;
}
public double getValue()
{
return value;
}
}
public class ProcessStuff {
public String process(GeneralStuff gS)
{
return doProcess(gS);
}
private String doProcess(IntStuff i)
{
return String.format("%d", i.getValue());
}
private String doProcess(DoubleStuff d)
{
return String.format("%f", d.getValue());
}
}
public class Test {
public static void main(String[] args)
{
IntStuff iS = new IntStuff();
DoubleStuff dS = new DoubleStuff();
ProcessStuff pS = new ProcessStuff();
iS.setValue(5);
dS.setValue(23.2);
System.out.println(pS.process(iS));
System.out.println(pS.process(dS));
}
}
This, however, doesn't work, because calling doProcess(gS)
expects a method with a signature doProcess(GeneralStuff gS)
.
I know I could just have two exposed polymorphic process methods in the ProcessStuff
class, but the actual situation won't allow it because I'm working within the constraints of an existing library mechanism; this is just a contrived example for testing.
I could, of course, define process(GeneralStuff gS)
as
public String process(GeneralStuff gS)
{
if (gS instanceof IntStuff)
{
return doProcess((IntStuff) gS);
}
else if (gS instanceof DoubleStuff)
{
return doProcess((DoubleStuff) gS);
}
return "";
}
which works, but it seems that I shouldn't have to do that (plus, the Programming Police would skewer me for using instanceof in this way).
Is there a way that I can enforce the polymorphic calls in a better way?
Thanks in advance for any help.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
如果不使用反射,您正在寻找的动态调度类型在 Java 中是不可能的。 Java 在编译时根据声明的类型进行链接(因此,即使方法被重载,实际调用的方法也是基于变量的声明类型而不是运行时类型)。
因此,您只能按照您的建议使用instanceof,使用反射,或者将过程方法放在对象本身中(这是“oop”方式,但通常不合适或不建议)。
一种潜在的替代方法是按类创建处理对象的映射,例如:
但是,对于您的特定示例,String.format 将对象作为参数,因此您可以通过在 GeneralStuff 中重写 getValue 和 getFormatString 方法来避免整个问题在具体的子类中。
The type of dynamic dispatch you are looking for is not possible in Java without using reflection. Java does its linking at compile time based on the declared type (so even though a method is overloaded, the actual method invoked is based on the declared type of the variable not the runtime type).
So you are left with either using instanceof as you propose, using reflection, or putting the process methods in the objects themselves (which is the "oop" way to do it, but is often not suitable or advisable).
One potential alternative is to create a map of processing objects by class, eg:
However, for your specific example, String.format takes objects as the parameters, so you could avoid this whole issue by having getValue and getFormatString methods in GeneralStuff which are overriden in the specific subclasses.
你实际上是在正确的轨道上,在这种情况下你确实需要使用反射。您正在寻找的是双重调度,因为您想要对 stuff 参数的动态类型进行分派。
这种类型的动态切换并不像您想象的那么罕见。例如,请参阅 此 javaworld 提示,它反映了 访客模式
You are actually on the right track, you indeed need to use reflection in this case. What you are looking for is sort of double dispatch, because you want the dispatch to be done on the dynamic type of the stuff parameter.
This type of switching-on-dynamic-type is not as rare as you think. See for example this javaworld tipe, which reflects on the visitor pattern
编译器的抱怨是有充分理由的。无法保证您的
GeneralStuff
对象是IntStuff
或DoubleStuff
。它可以是普通的GeneralStuff
或GeneralStuff
的任何其他扩展,这种情况您也没有在process
方法中使用 < code>instanceof (除非返回空的String
是所需的行为)。是否无法将该
process
方法移至GeneralStuff
类中并在扩展中覆盖它?另一种可能的解决方案是使用一种复合
ProcessStuff
类,在其中插入IntStuffProcess
、DoubleStuffProcess
, ... 实例。这些实例中的每一个仍将进行instanceof检查,以决定它们是否可以处理传递给它们的GeneralStuff对象,但这至少比一个大的instanceof构造更具可扩展性/可维护性The compiler complains for good reason. There is no guarantee that your
GeneralStuff
object is anIntStuff
or aDoubleStuff
. It can be a plainGeneralStuff
or any other extension ofGeneralStuff
, which is a case you also did not cover in yourprocess
method with theinstanceof
(unless returning the emptyString
was the desired behavior).Is it not possible to move that
process
method into theGeneralStuff
class and override it in the extensions ?Another possible solution is to have a sort of composite
ProcessStuff
class in which you plug aIntStuffProcess
,DoubleStuffProcess
, ... instance . Each of those instances will still have the instanceof check to decide whether they can handle theGeneralStuff
object passed to them, but this is at least more scalable/maintainable then one big instanceof construct也许,最好在
ProcessStuff
中重载process
方法:Perhaps, it's better to have overloaded
process
method inProcessStuff
:将 GeneralStuff 定义为抽象类,并在继承类中填充 doProcess 方法(抽象)。这样您就可以避免所有有关 instanceof 值等的问题。或者你可以按照 βнɛƨн Ǥʋяʋиɢ 的建议进行操作,但是你仍然必须为每个特定类定义一个重载,而在我的方法中你只需直接调用它。
所以我的建议是:
公共抽象类 GeneralStuff {
私有 int ID;
Define an GeneralStuff as an abstract class, with a doProcess method (abstract) which is filled in in the inheriting classes. This way you avoid all problems with instanceof values and such. Or you can do what is suggested by βнɛƨн Ǥʋяʋиɢ, but then you still would have to define an overload for each specific class, whereas in mine you just call it directly.
So my suggestion would be:
public abstract class GeneralStuff {
private int ID;