Java 使用通用父类型输入参数强制执行动态多态调用
我尝试使用多态性来根据对象的类对其进行不同的处理,如下所示:Java 使用通用父类型输入参数强制执行动态多态调用,java,dynamic,polymorphism,parent,Java,Dynamic,Polymorphism,Parent,我尝试使用多态性来根据对象的类对其进行不同的处理,如下所示: public class GeneralStuff { private int ID; } public class IntStuff extends GeneralStuff { private int value; public void setValue(int v) { value = v; } public int getValue() {
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
类中有两个公开的多态过程方法,但实际情况不允许这样做,因为我在现有库机制的约束下工作;这只是一个人为的测试示例
当然,我可以将过程(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而对我进行指责)
有没有一种方法可以更好地执行多态调用
提前感谢您的帮助。也许,最好在
ProcessStuff
中重载process
方法:
public class ProcessStuff {
private String process(IntStuff i) {
return String.format("%d", i.getValue());
}
private String process(DoubleStuff d) {
return String.format("%f", d.getValue());
}
}
使用在继承类中填充的doProcess方法(抽象)将GeneralStuff定义为抽象类。这样可以避免instanceof值等的所有问题。或者,您可以按照βɛƨǤʋʋɢ的建议执行操作,但是您仍然需要为每个特定类定义一个重载,而在我的类中,您只需直接调用它 因此,我的建议是: 公共抽象类GeneralStuff{ 私有int-ID
public abstract String process();
}
public class IntStuff extends GeneralStuff {
private int value;
public void setValue(int v)
{
value = v;
}
public int getValue()
{
return value;
}
@override
public String process(){
return String.format("%d", getValue());
}
}
public class DoubleStuff extends GeneralStuff {
private double value;
public void setValue(double v)
{
value = v;
}
public double getValue()
{
return value;
}
@override
public String process(){
return String.format("%f", 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(iS.process());
System.out.println(dS.process());
}
}
编译器抱怨是有充分理由的。不能保证
GeneralStuff
对象是IntStuff
或DoubleStuff
。它可以是普通的GeneralStuff
或GeneralStuff
的任何其他扩展,这是您在过程中使用instanceof
(除非返回空的字符串
是所需的行为)
无法将进程
方法移动到GeneralStuff
类中并在扩展中重写它吗
另一种可能的解决方案是使用一种复合的ProcessStuff
类,在该类中插入一个IntStuffProcess
,DoubleStuffProcess
,…实例。这些实例中的每一个都将仍然具有instanceof check,以确定它们是否可以处理传递给它们的GeneralStuff
对象,但这是一种情况至少比构造的一个大实例更具可伸缩性/可维护性在Java中,如果不使用反射,您所寻找的动态分派类型是不可能的。Java在编译时根据声明的类型进行链接(因此,即使方法重载,实际调用的方法也基于声明的变量类型,而不是运行时类型)
因此,您要么按照您的建议使用instanceof,要么使用反射,要么将流程方法放入对象本身(这是“oop”方式,但通常不合适或不可取)
一种可能的替代方法是按类创建处理对象的映射,例如:
Map<Class<? extends GeneralStuff>,Processor> processors;
public String process(GeneralStuff stuff)
{
Processor processor = processors.get(stuff.getClass());
if (processor != null)
{
return processor.process(stuff);
}
}
public interface Processor
{
public String process(GeneralStuff stuff);
}
public class IntegerProcessor implements Processor
{
public String process(GeneralStuff stuff)
{
return String.format("%i",((IntegerStuff) stuff).getValue());
}
}
Map实际上,您的思路是正确的,在这种情况下确实需要使用反射。您需要的是某种程度上的反射,因为您希望在stuff参数的动态类型上完成分派
这种类型的动态类型并不像你想象的那么少见。例如,这反映在上,这是一种基于类重定向的聪明方法。我相信,Map
也可以用于将流引导到ProcessStuff
类中的不同方法。谢谢!在实际应用中,t参数对象(IntStuff
,DoubleStuff
)作为GeneralStuff
的实例打包到一个Bundle
对象中,然后传递给另一个(ProcessStuff
)对象进行处理,其中参数对象被拉出,并根据它们的实际类型采取不同的操作。因此,我实际上没有选择在ProcessStuff
中提供直接调用的重载处理方法(由@βɛƨǤʋɢ建议),并且将过程
方法移动到通用tuff
中也可能不是一个选项(由您和@codegrabber建议)。