没有继承,多态是否可能? [英] Is polymorphism possible without inheritance?

查看:116
本文介绍了没有继承,多态是否可能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在一次采访中,我被问到是否可以在没有继承的情况下实现多态性。这可能吗?

In an interview I was asked if polymorphism can be achieved without inheritance. Is this possible?

推荐答案

我读过的关于这个主题的最佳解释是 Luca Cardelli ,一位着名的理论家。该文章名为了解类型,数据抽象和多态性

The best explanation on the subject that I've ever read is an article by Luca Cardelli, a renown type theorist. The article is named On Understanding Types, Data Abstraction, and Polymorphism.

Cardelli在本文中定义了几种类型的多态:

Cardelli defines several types of polymorphism in this article:


  • 通用


    • 参数

    • 包含


    • 重载

    • 强制

    与继承相关的多态性类型被归类为包含多态性或子类型多态性。

    The kind of polymorphism related to inheritance is classified as inclusion polymorphism or subtype polymorphism.

    维基百科提供一个好的定义:


    在面向对象的编程中,子类型多态或包含
    多态是类型理论中的一个概念,其中一个名称可以表示
    的人类实例y不同的类,只要它们与
    相关,就是一些常见的超类。包含多态性通常是通过子类型支持
    ,即不同类型的对象是
    完全可替代另一种类型的对象(它们的基本
    类型),因此可以通过公共处理接口。
    或者,包含多态性可以通过类型
    强制来实现,也称为类型转换。

    In object-oriented programming, subtype polymorphism or inclusion polymorphism is a concept in type theory wherein a name may denote instances of many different classes as long as they are related by some common super class. Inclusion polymorphism is generally supported through subtyping, i.e., objects of different types are entirely substitutable for objects of another type (their base type(s)) and thus can be handled via a common interface. Alternatively, inclusion polymorphism may be achieved through type coercion, also known as type casting.

    另一个维基百科名为面向对象编程中的多态性的文章似乎也回答了你的问题。

    Another Wikipedia article called Polymorphism in object-oriented programming seems to answer your questions as well.

    Java中的这种子类型功能是通过继承类和接口来实现的。尽管Java的子类型特征在继承方面可能并不明显。以协方差和与泛型的逆变为例。此外,数组是Serializable和Cloneable,尽管在类型层次结构中的任何位置都不明显。也可以说,通过原始扩展转换,Java中的数字运算符是多态的,在某些情况下甚至接受完全不相关的操作数(即字符串和数字或字符串加上一些其他对象的串联)。还要考虑基元的装箱和拆箱的情况。后面这些多态(强制和重载)的情况与继承完全无关。

    This subtyping feature in Java is achieved, among other means, through inheritance of classes and interfaces. Although the subtyping features of Java may not be evident in terms of inheritance all the time. Take for example the cases of covariance and contravariance with generics. Also, arrays are Serializable and Cloneable although this is not evident anywhere in the type hierarchy. It can also be said that through primitive widening conversion the numeric operators in Java are polymorphic, in certain cases even accepting totally unrelated operands (i.e. concatenation of strings and numbers or of a string plus some other object). Consider also the cases of boxing and unboxing of primitives. These latter cases of polymorphism (coercions and overloading) are not at all related to inheritance.

    包含

    List<Integer> myInts = new ArrayList<Integer>();
    

    这是您的问题似乎引用的情况,即当存在继承或实现关系时这个类型,就像在这种情况下ArrayList实现List一样。

    This is the case to which your question seems to refer i.e. when there is an inheritance or implementation relationship between the types, as in this case where ArrayList implements List.

    正如我所提到的,当你引入Java泛型时,有时候子类型的规则会变得模糊:

    As I mentioned, though, when you introduce Java generics, some time the rules of subtyping get fuzzy:

    List<? super Number> myObjs = new ArrayList<Object>();
    List<? extends Number> myNumbers = new LinkedList<Integer>();
    

    在其他情况下,API中的关系甚至不明显

    And in other cases, the relationships are not even evident in the API

    Cloneable clone = new int[10];
    Serializable obj = new Object[10]
    

    即便如此,所有这些,根据Cardelli的说法,是通用多态的形式。

    Even so, all these, according to Cardelli, are forms of universal polymorphism.

    参数

    public <T> List<T> filter(Predicate<T> predicate, List<T> source) {
      List<T> result = new ArrayList<>();
      for(T item : source) {
        if(predicate.evaluate(item)){
             result.add(item);
        }
       return result;
      }
    }
    

    可以使用相同的算法过滤所有种类的列出所有类型的谓词,而不必为每种可能类型的列表重复单行代码。实际列表的类型和谓词的类型是参数化的。使用 JDK 8 Preview 中提供的lambda表达式查看此示例(为了简化谓词实现)。

    The same algorithm can be used to filter all kinds of lists with all kinds predicates without having to repeat a single line of code for every possible type of list. The type of the actual list and the type of predicate are parametric. See this example with lambda expressions available in JDK 8 Preview (for brevity of predicate implementation).

    filter(x -> x % 2 == 0, asList(1,2,3,4,5,6)); //filters even integers
    filter(x -> x % 2 != 0, asList(1L,2L,3L,4L,5L,6L)); //filters odd longs
    filter(x -> x >= 0.0, asList(-1.0, 1.0)); //filters positive doubles
    

    根据Cardelli的说法,这是一种通用多态性。

    According to Cardelli, this is a form of universal polymorphism.

    强制

    double sum = 1 + 2.0;
    

    整数和浮点运算完全不同。如果没有某种形式的强制,将plus运算符应用于两个不同类型的操作数是不可能的。

    Integer and floating-point arithmetic are totally different. Applying the plus operator to two operands of different types here is impossible without some form of coercion.

    在此示例中,类型为integer和double,会自动强制转换(转换)在没有显式转换的情况下输入double。整个表达式被提升为双倍。这是因为在Java中我们有原始的扩展转换。

    In this example, the types integer and double,are automatically coerced (converted) to type double without an explicit cast. The entire expression is promoted to double. This is so because in Java we have primitive widening conversions.

    根据Cardelli的说法,这种形式的自动强制是为加号运算符提供的一种ad-hoc多态。

    According to Cardelli, this form of automatic coercion is a form of ad-hoc polymorphism provided for the plus operator.

    有些语言甚至无法对没有显式强制转换的整数和浮点数求和(即AFAIK,SML,顺便说一下,参数多态是克服这类问题的关键)。

    There are languages in which you could not even sum an integer and a floating-point number without an explicit cast (i.e. AFAIK, SML, in which, by the way, parametric polymorphism is key to overcome this kind of problems).

    超载

    double sum = 2.0 + 3.0;
    String text = "The sum is" + sum;
    

    这里的加号运算符意味着两种不同的东西,具体取决于所使用的参数。显然,操作员已经超负荷运转。这意味着它具有不同的实现,具体取决于操作数的类型。根据Cardelli的说法,这是为plus运算符提供的一种ad-hoc多态。

    The plus operator here means two different things depending on the arguments used. Evidently, the operator has been overloaded. This implies it has different implementations depending on the types of operands. According to Cardelli, this is a form of ad-hoc polymorphism provided for the plus operator.

    当然,这也适用于类中方法重载的形式(即重载java.lang.Math方法min和max以支持不同的基本类型。)

    This, of course, also applies to forms of method overloading in classes (i.e java.lang.Math methods min and max are overloaded to support different primitive types).

    即使继承在实现某些形式的多态中起着重要作用,当然它也不是唯一的方法。其他非面向对象的语言提供其他形式的多态性。以动态语言(如Python)甚至静态类型的鸭子打字为例像Go这样的语言,或者像SML,Ocaml和Scala等语言中的代数数据类型,或者类型类,如Haskell,多种方法,JavaScript中的原型继承等。

    Even when inheritance plays an important role in the implementation of some of these forms of polymorphism, certainly it is not the only way. Other languages that are not object-oriented provide other forms of polymorphism. Take, for example, the cases of duck typing in dynamic languages like Python or even in statically-typed languages like Go, or algebraic data types in languages like SML, Ocaml and Scala, or type classes in languages like Haskell, multi methods in Clojure, prototypal inheritance in JavaScript, etc.

    这篇关于没有继承,多态是否可能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆