没有继承可以实现多态吗? [英] Is polymorphism possible without inheritance?

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

问题描述

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

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.

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

    Wikipedia provides a good definition:

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

    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 的子类型特性在继承方面可能并不总是很明显.以泛型的协变和逆变为例.此外,数组是可序列化和可克隆的,尽管这在类型层次结构中的任何地方都不明显.也可以说,通过原始扩展转换,Java 中的数字运算符是多态的,在某些情况下甚至可以接受完全不相关的操作数(即字符串和数字的连接或字符串与其他对象的连接).还要考虑原语装箱和拆箱的情况.后面这些多态(强制和重载)的情况与继承完全没有关系.

    This subtyping feature in Java is achieved, among other means, through the 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 (coercion 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 of 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 the 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;
    

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

    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 的说法,这种形式的自动强制是为加号运算符提供的一种特殊多态形式.

    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 的说法,这是为加号运算符提供的一种特殊多态性形式.

    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天全站免登陆