java 没有继承可以实现多态吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11732422/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 06:10:45  来源:igfitidea点击:

Is polymorphism possible without inheritance?

javaoopinheritancepolymorphism

提问by Just_another_developer

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

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

回答by Edwin Dalorzo

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.

我读过的关于这个主题的最佳解释是著名类型理论家Luca Cardelli的一篇文章。这篇文章的名字是关于理解类型、数据抽象和多态

Types of Polymorphism

多态的类型

Cardelli defines several types of polymorphism in this article:

Cardelli 在这篇文章中定义了几种类型的多态:

  • Universal
    • parametric
    • inclusion
  • Ad-hoc
    • overloading
    • coercion
  • 普遍的
    • 参数
    • 包容
  • 特别指定
    • 超载
    • 强迫

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

与继承有关的多态性分为包含多态性或亚型多态性。

Wikipediaprovides a good definition:

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

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 programmingseems to answer your questions as well.

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

In 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.

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

Examples

例子

Inclusion

包容

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

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.

这就是您的问题似乎所指的情况,即当类型之间存在继承或实现关系时,就像在这种情况下 ArrayList 实现 List。

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

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

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

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

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

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

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

尽管如此,根据 Cardelli 的说法,所有这些都是通用多态性的形式。

Parametric

参数

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

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).

相同的算法可用于过滤具有各种谓词的各种列表,而无需为每种可能的列表类型重复一行代码。实际列表的类型和谓词的类型是参数化的。请参阅此示例,其中包含JDK 8 预览版中可用的 lambda 表达式(为了谓词实现的简洁性)。

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

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

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

Coercion

强迫

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.

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

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.

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

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

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

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).

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

Overloading

超载

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

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.

此处的加号运算符根据所使用的参数有两种不同的含义。显然,操作符已经过载。这意味着它根据操作数的类型有不同的实现。根据 Cardelli 的说法,这是为加号运算符提供的一种特殊多态性形式。

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).

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

In Other Languages

其他语言

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 typingin dynamic languages like Python or even in statically-typed languages like Go, or algebraic data typesin languages like SML, Ocaml and Scala, or type classesin languages like Haskell, multi methodsin Clojure, prototypal inheritancein JavaScript, etc.

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

回答by Amitabha Roy

Ad-hoc Polymorphism > Operator Overloading > Without Inheritence

即席多态 > 运算符重载 > 无继承

Ad-hoc Polymorphism > Method Overloading > Without Inheritence

即席多态 > 方法重载 > 无继承

Ad-hoc Polymorphism > Method Overriding > With Inheritence

即席多态性 > 方法覆盖 > 具有继承性

Parametric Polymorphism > Generics > Without Inheritence

参数多态 > 泛型 > 无继承

Subtype Polymorphism or Inclusion Polymorphism > Polymorphic Assignment > With Inheritence

子类型多态或包含多态 > 多态赋值 > 有继承

Subtype Polymorphism or Inclusion Polymorphism > Polymorphic Return Type > With Inheritence

子类型多态或包含多态 > 多态返回类型 > 有继承

Subtype Polymorphism or Inclusion Polymorphism > Polymorphic Argument Type > With Inheritence

子类型多态或包含多态 > 多态参数类型 > 具有继承性

Coercion Polymorphism > Widening > With or without Inheritence

强制多态性 > 加宽 > 有或没有继承

Coercion Polymorphism > Auto boxing and unboxing > Without Inheritence

强制多态 > 自动装箱和拆箱 > 无继承

Coercion Polymorphism > Var args > Without Inheritence

强制多态 > Var args > 无继承

Coercion Polymorphism > Type Casting > Without Inheritence

强制多态 > 类型转换 > 无继承

回答by Max

Sure. In Java, you can have two classes implement the same interface, and their results are polymorphic. No functionality is inherited.

当然。在 Java 中,您可以让两个类实现相同的接口,并且它们的结果是多态的。不继承任何功能。

public interface Foo {
  public int a();
}

public class A implements Foo {
  public int a() {
    return 5;
  }
}


public class B implements Foo {
  public int a() {
    return 6;
  }
}

Then elsewhere:

然后在别处:

Foo x = new A();
System.out.println(x.a())
Foo y = new B();
System.out.println(y.a())

Both xand yare Foos, but they have different results when you call a().

这两个xyFooS中,但有不同的结果,当你打电话a()

回答by Arun

Static type

静态类型

overloading - which means multiple methods with same name but different signature which is possible with out overriding

重载 - 这意味着多个具有相同名称但不同签名的方法,无需覆盖即可

class StaticPolyExample
{
void print(int s)
{
    //print s
}

void print(String s)
{
    //print s
}

}

Dynamic type

动态型

overriding - which means the method in super class will be re-defined in sub class which needs inheritance

覆盖 - 这意味着超类中的方法将在需要继承的子类中重新定义

class Printer
{
void print(String s)
{
  // prints String
}

}

class diffPrinter extends Printer
{
void print(String s)
{
  // prints String differently
}

}

回答by Danil Speransky

Yes, I think they probably wanted to hear about polymorphism by interfaces. So if there 2 classes which implements from the same interface, then we can use in all places where we exspect an object with such intervace. See code from wikipedia:

是的,我认为他们可能想通过接口了解多态性。因此,如果有 2 个从同一接口实现的类,那么我们可以在我们期望具有此类间隔的对象的所有地方使用。请参阅维基百科的代码:

// from file Animal.java

public interface Animal {
        public String talk();
}

// from file Cat.java

public class Cat implements Animal {
        @Override
        public String talk() {
                return "Cat says Meow!";
        }
}

// from file Dog.java

public class Dog implements Animal {
        @Override
        public String talk() {
                return "Dog says Woof! Woof!";
        }
}

// from file PolymorphismExample.java

public class PolymorphismExample {

        public static void main(String[] args) {
                Collection<Animal> animals = new ArrayList<Animal>();
                animals.add(new Cat());
                animals.add(new Dog());

                for (Animal a : animals) {
                        System.out.println(a.talk());
                }
        }

}

回答by Dhananjay

Function overloading is one of the polymorphism (though it's not what real polymorphism is meant) which can be achieved without inheritance.

函数重载是一种无需继承即可实现的多态性(尽管它不是真正的多态性的含义)。

e.g.

例如

class Foo { 
public void Arrest( Animal A){
    /*code...*/
 }  
public void Arrest( Terrorist T ) {
    /*code...*/
 }  

}


from main :

Foo f= new Foo();
f.Arrest( new Lion() );
f.Arrest(new Terrorist());

Arrest method is called 2 times but the path of execution of the code is different.

Arrest 方法被调用了 2 次,但代码的执行路径不同。

*Again this is not true form of polymorphism. Real polymorphism in General can not be acheived without inheritance.

*同样,这不是多态性的真正形式。真正的多态一般来说没有继承是无法实现的。