方法重载&多态性 - 什么是更简洁的方法呢?

时间:2011-08-05 16:18:21

标签: java polymorphism overloading

检查以下代码示例:

public class Test
{
    private void process(Instance1 obj)
    {
        System.out.println("Process Instance 1");
    }

    private void process(Instance2 obj)
    {
        System.out.println("Process Instance 2");
    }

    /* 
    COMMENT THIS OUT - I DON'T HAVE THIS CODE IN REAL LIST. Only here to prove point 3 below calls this
    private void process(SuperClass obj)
    {
        System.out.println("Process superclass");
    }
    */

    /**
     * @param args
     */
    public static void main(String[] args)
    {
        Test test = new Test();
        Instance1 instance1 = test.new Instance1();
        Instance2 instance2 = test.new Instance2();
        SuperClass instance3 = test.new Instance1();

        // test #1          
        test.process(instance1);
        // test #2          
        test.process(instance2);
        // test #3 (compiler error unless there is a process(SuperClass obj) call)
        test.process(instance3);
        // test #4                      
        if(instance3 instanceof Instance1)
            test.process((Instance1)instance3);
        else if(instance3 instanceof Instance2)
            test.process((Instance2)instance3);

    }

    abstract class SuperClass
    {
    }

    class Instance1 extends SuperClass
    {
    }

    class Instance2 extends SuperClass
    {
    }
}

这给出了输出:

Process Instance 1
Process Instance 2
Process superclass
Process Instance 1

我希望测试#3知道调用正确的函数,但似乎没有。我想这是编译时的事情,而不是运行时的事情。选项#4有效,但很难看,我希望有更好的方法。

更新:澄清问题......我有一个抽象类,其中存在两个具体的实现。我想要的是在另一个类中有两个重载方法(每个具体类一个),并且能够在不执行任何实例的情况下调用它。从我现在所知,这是不可能的,因为这是一个编译时问题,编译器显然不知道当它没有强类型时它是什么具体的类。

6 个答案:

答案 0 :(得分:3)

这不是多态性的问题。这是方法重载的问题。

当您将instance3传递给process()时,它会调用process(SuperClass obj),因为只要JVM知道,instance3就是SuperClass,因为那是什么你宣布它为。

如果您想要所需的行为(测试#3打印出“Process Instance 1”),您应该定义process()方法,如下所示:

private void process(SuperClass obj)
{
    System.out.println("Process " + obj.name());
}

你的课程是这样的:

abstract class SuperClass
{
    String name() {
        return "SuperClass";
    }
}

class Instance1 extends SuperClass
{
    String name() {
        return "Instance 1";
    }
}

class Instance2 extends SuperClass
{
    String name() {
        return "Instance 2";
    }
}

这将因动态(或延迟)方法绑定而起作用。

答案 1 :(得分:0)

将其作为层次结构中的虚函数:

abstract class SuperClass
{
    public void process() { System.out.println("Process super class"); } 
}

class Instance1 extends SuperClass
{
    public void process() { System.out.println("Process instance1"); } 
}

class Instance2 extends SuperClass
{
    public void process() { System.out.println("Process instance2"); } 
}

或将various approaches签出到Java本身不支持的多个分派。

答案 2 :(得分:0)

为更清洁地做你正在做的事情提供建议:

选项1:抽象方法process()上定义Superclass,并在Instance1Instance2上覆盖它:

abstract class SuperClass
{
    public void process(String[] args)
    {
        System.out.println("Process superclass");
    }
}

class Instance1 extends SuperClass
{
    @Override
    public void process(String[] args)
    {
        System.out.println("Process Instance 1");
    }
}

class Instance2 extends SuperClass
{
    @Override
    public void process(String[] args)
    {
        System.out.println("Process Instance 2");
    }
}

选项2:访客模式 定义执行处理的类,并且是InstanceVisitor

public interface InstanceVisitor
{

    public void processSuperclass(Superclass obj, String[] args);

    public void processInstance1(Instance1 obj, String[] args);

    public void processInstance2(Instance2 obj, String[] args);

}

public class InstanceProcessor implements InstanceVisitor
{

    public void processSuperclass(Superclass obj, String[] args)
    {
        System.out.println("Process superclass");
    }

    public void processInstance1(Instance1 obj, String[] args)
    {
        System.out.println("Process Instance 1");
    }

    public void processInstance2(Instance2 obj, String[] args)
    {
        System.out.println("Process Instance 2");
    }

}

然后每个子类接受一个访问者,并调用正确的方法:

abstract class SuperClass
{
    public void accept(InstanceVisitor v, String[] args)
    {
        v.visitSuperclass(this, args);
    }
}

class Instance1 extends SuperClass
{
    @Override
    public void accept(InstanceVisitor v, String[] args)
    {
        v.visitInstance1(this, args);
    }
}

class Instance2 extends SuperClass
{
    @Override
    public void accept(InstanceVisitor v, String[] args)
    {
        v.visitInstance2(this, args);
    }
}

答案 3 :(得分:0)

您可以更改SuperClassInstance吗?如果是这样,您应该声明抽象方法SuperClass.process()并在子类中实现它。

要使测试#3正常工作,您可以添加强制转换:test.process((Instance1)instance3);。难看。

您还可以定义工厂类,并在其中封装类型切换。 您有ProcessFactory ProcessObject getInstance(SuperClass obj)方法可返回类型为ProcessObjectInstance1ProcessObjectInstance2的对象,方法为process()ProcessFactory与您的测试#4类似。

答案 4 :(得分:0)

这就是我目前正在做的事情。基本上把问题解决了一下。不确定这是否算作访客模式。

基本上我只是在SuperClass中添加了一个executeProcessor(测试测试)抽象函数,具体类隐式知道要调用哪个函数,所以他们可以简单地使用强制转换。

你怎么看?这个代码有异味吗?还是一个简洁的解决方案?

public class Test
{
    private void process(Instance1 obj)
    {
        System.out.println("Process Instance 1");
    }

    private void process(Instance2 obj)
    {
        System.out.println("Process Instance 2");
    }

    /**
     * @param args
     */
    public static void main(String[] args)
    {
        Test test = new Test();

        // Test 1
        Instance1 instance1 = test.new Instance1();
        instance1.executeProcessor(test);

        // Test 2
        Instance2 instance2 = test.new Instance2();
        instance2.executeProcessor(test);

        // Test 3 (note this is not strongly typed)
        SuperClass instance3 = test.new Instance1();
        instance3.executeProcessor(test);
    }

    abstract class SuperClass
    {
        public abstract void executeProcessor(Test test);
    }

    class Instance1 extends SuperClass
    {

        @Override
        public void executeProcessor(Test test)
        {
            test.process((Instance1)this);
        }
    }

    class Instance2 extends SuperClass
    {

        @Override
        public void executeProcessor(Test test)
        {
            test.process((Instance2)this);
        }
    }
}

答案 5 :(得分:0)

正如其他人所指出的,这不是你在Java中可以做的事情。如果你绝对必须,你可以使用反射来做类似的事情:

private void process(SuperClass obj)
{
  try
  {
     Class<? extends SuperClass> klass = obj.getClass();
     Method m = this.getClass().getMethod("process", klass);
     m.invoke(this, obj);
  }
  catch (Exception e)
  {
     // default behavior
     System.out.println("Process superclass");
  }
}

我真的会遵循其他建议之一。