【问题标题】:method overloading & polymorphism - what is a cleaner way to do this?方法重载和多态性 - 什么是更清洁的方法?
【发布时间】:2011-08-05 16:18:21
【问题描述】:

检查以下代码示例:

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 有效,但很难看,我希望有更好的方法。

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

【问题讨论】:

  • 搜索“双重调度”。

标签: java polymorphism overloading


【解决方案1】:

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

当您将instance3 传递给process() 时,它会调用process(SuperClass obj),因为据JVM 所知,instance3SuperClass,因为这就是您声明的内容。

如果你想要想要的行为(test#3 打印出“进程实例 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";
    }
}

由于动态(或后期)方法绑定,这将起作用。

【讨论】:

  • 我并没有真正将其作为解决方案。我需要的是调用正确的 process() 函数。打印出来的内容与演示无关。我正在尝试找到比使用 instanceof 运算符更好的解决方案。
【解决方案2】:

你能改变SuperClassInstances吗?如果是这样,你应该声明抽象方法SuperClass.process()并在子类中实现它。

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

您还可以定义一个工厂类,并在其中封装类型切换。 您将拥有ProcessFactoryProcessObject getInstance(SuperClass obj) 方法,该方法返回ProcessObjectInstance1ProcessObjectInstance2 类型的对象,以及process() 方法。 ProcessFactory 的工作方式与您的测试#4 类似。

【讨论】:

    【解决方案3】:

    这是我目前正在做的。基本上把问题从里到外翻了一点。不确定这是否算作访客模式。

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

    你怎么看?这段代码有味道吗?还是一个巧妙的解决方案?

    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);
            }
        }
    }
    

    【讨论】:

      【解决方案4】:

      正如其他人所指出的,这并不是您可以在 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");
        }
      }
      

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

      【讨论】:

        【解决方案5】:

        关于更清洁的方式来做你正在做的事情的几个建议:

        选项 1:抽象方法Superclass 上定义process(),并在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);
            }
        }
        

        【讨论】:

        • 我对上一篇文章有​​类似的评论。 process() 函数将 SuperClass 的实例作为参数。它里面没有 process() 函数。我要澄清原来的问题
        【解决方案6】:

        要么让它成为层次结构中的虚函数:

        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 原生不支持的多个调度。

        【讨论】:

        • process() 调用将超类(或子类)作为参数。它不是超类的一部分
        猜你喜欢
        • 1970-01-01
        • 2011-06-25
        • 2011-06-22
        • 1970-01-01
        • 2023-03-23
        • 2022-12-16
        • 1970-01-01
        • 2017-06-06
        • 2010-11-14
        相关资源
        最近更新 更多