Java中的重载和多分派

2022-01-24 00:00:00 oop overloading polymorphism java

我有一个集合(或列表或数组列表),我想在其中放置字符串值和双精度值.我决定让它成为一个对象的集合并使用重载和多态性,但是我做错了.

I have a collection (or list or array list) in which I want to put both String values and double values. I decided to make it a collection of objects and using overloading ond polymorphism, but I did something wrong.

我运行了一个小测试:

public class OOP {
    void prova(Object o){
        System.out.println("object");
    }

    void prova(Integer i){
    System.out.println("integer");
    }

    void prova(String s){
        System.out.println("string");
    }

    void test(){
        Object o = new String("  ");
        this.prova(o); // Prints 'object'!!! Why?!?!?
    }

    public static void main(String[] args) {
        OOP oop = new OOP();
        oop.test(); // Prints 'object'!!! Why?!?!?
    }
}

在测试中,参数类型似乎是在编译时而不是在运行时决定的.这是为什么呢?

In the test seems like the argument type is decided at compile time and not at runtime. Why is that?

这个问题与:

多态性 vs 覆盖 vs 重载
尝试尽可能简单地描述多态性

好的,要调用的方法是在编译时决定的.是否有避免使用 instanceof 运算符的解决方法?

Ok the method to be called is decided at compile time. Is there a workaround to avoid using the instanceof operator?

推荐答案

这篇文章秒了voo的答案,并提供了有关后期绑定/替代方案的详细信息.

This post seconds voo's answer, and gives details about/alternatives to late binding.

一般 JVM 只使用 single dispatch:运行时类型只考虑接收者对象;对于方法的参数,考虑静态类型.使用 方法表 (类似于 C++ 的虚拟表).您可以找到详细信息,例如在 HotSpot Wiki 中.

General JVMs only use single dispatch: the runtime type is only considered for the receiver object; for the method's parameters, the static type is considered. An efficient implementation with optimizations is quite easy using method tables (which are similar to C++'s virtual tables). You can find details e.g. in the HotSpot Wiki.

如果您希望参数多次调度,请查看

If you want multiple dispatch for your parameters, take a look at

  • groovy.但据我所知,它有一个过时的、缓慢的多调度实现(参见例如 这个性能比较),例如没有缓存.
  • clojure,但这与 Java 完全不同.
  • MultiJava,它为 Java 提供了多重调度.此外,您可以使用
    • this.resend(...) 而不是 super(...) 来调用封闭方法的最具体的重写方法;
    • 值调度(下面的代码示例).
    • groovy. But to my latest knowledge, that has an outdated, slow multiple dispatch implementation (see e.g. this performance comparison), e.g. without caching.
    • clojure, but that is quite different to Java.
    • MultiJava, which offers multiple dispatch for Java. Additionally, you can use
      • this.resend(...) instead of super(...) to invoke the most-specific overridden method of the enclosing method;
      • value dispatching (code example below).

      如果你想坚持使用 Java,你可以

      • 通过在更细粒度的类层次结构上移动重载方法来重新设计您的应用程序.Josh Bloch 的 Effective Java 项目中给出了一个示例41(明智地使用重载);
      • 使用一些设计模式,例如策略、访问者、观察者.这些通常可以解决与多分派相同的问题(即,在那些情况下,对于使用多分派的那些模式,您有一些简单的解决方案).
      • redesign your application by moving overloaded methods over a finer grained class hierarchy. An example is given in Josh Bloch's Effective Java, Item 41 (Use overloading judiciously);
      • use some design patterns, such as Strategy, Visitor, Observer. These can often solve the same problems as multiple dispatch (i.e. in those situations you have trivial solutions for those patterns using multiple dispatch).

      值调度:

      class C {
        static final int INITIALIZED = 0;
        static final int RUNNING = 1;
        static final int STOPPED = 2;
        void m(int i) {
          // the default method
        }
        void m(int@@INITIALIZED i) {
          // handle the case when we're in the initialized `state'
        }
        void m(int@@RUNNING i) {
          // handle the case when we're in the running `state'
        }
        void m(int@@STOPPED i) {
          // handle the case when we're in the stopped `state'
        }
      }
      

相关文章