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建议)。