在接受采访时有人问我是否可以在不继承实现多态性。 这可能吗?
Answer 1:
对我读过的主题最好的解释是通过文章卢卡·卡迪利 ,一个著名理论家类型。 这篇文章被命名为于理解类型,数据抽象,和多态性 。
多态的类型
Cardelli定义了几种类型的多态性在这篇文章中的:
- 普遍
- 参数
- 包容
- 特设
- 超载
- 强迫
那种多态性与遗传有关的被列为列入多态性或亚型多态性。
维基百科提供了一个很好的定义:
在面向对象的编程中,亚型多态性或多态性包含在类型理论概念,其中的名称可以表示许多不同的类的实例,只要它们是由一些共同的超类相关。 夹杂物的多态性通过子类型一般都支持的,即,不同类型的对象是另一种类型的(它们的基本类型(一个或多个))的对象完全取代,因此可以通过一个共同的接口来处理。 可替代地,包含基因多态性可以通过类型强制,也被称为类型转换来实现。
另一个维基百科的文章被称为面向对象编程的多态性似乎回答您的问题也是如此。
在Java
在Java中这一亚型的特征得以实现,除其他手段,通过类和接口的继承。 尽管Java的子类型特征继承权可能不明显所有的时间。 就拿协方差的情况下,并与仿制药逆变。 此外,阵列是序列化和Cloneable的虽然这在类型层次结构的任何地方并不明显。 还可以说,通过原语加宽转换Java中的数字运算符是多态的,在某些情况下,甚至在接受完全无关的操作数(即,字符串和数字的或字符串的级联加上一些其它对象)。 想想也是拳击和基本类型的拆箱的情况。 这些多态性后面的情况(强制和重载)是不是在所有与遗传有关。
例子
入选
List<Integer> myInts = new ArrayList<Integer>();
这是该你的问题似乎是指即当有各类型之间的继承或实现关系,在这种情况下的ArrayList实现列表的情况。
正如我所提到的,不过,当你介绍Java泛型,一段时间亚型的规则得到模糊:
List<? super Number> myObjs = new ArrayList<Object>();
List<? extends Number> myNumbers = new LinkedList<Integer>();
而在其他情况下,关系不是在API中甚至明显
Cloneable clone = new int[10];
Serializable obj = new Object[10]
即便如此,所有这些,根据Cardelli,是普遍的多态性的形式。
参数
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;
}
}
相同的算法可被用于过滤各种各类谓词的列表,而无需重复的一行代码每一个可能的类型的列表。 该类型的实际列表和谓语的类型是参数化的。 看到在可用lambda表达式这个例子JDK 8预览 (为谓词实现的简洁)。
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,这是普遍的多态性的一种形式。
强迫
double sum = 1 + 2.0;
整数和浮点运算是完全不同的。 运用加上运营商不同类型的两个操作数没有某种形式的胁迫这里是不可能的。
在这个例子中,整数和双,被自动强制(经换算)的类型,而无需显式转换double类型。 整个表达式被提升到一倍。 这是因为在Java中,我们有原始的扩大转换。
根据Cardelli,这种形式的自动强制的是规定的加运算特设多态的一种形式。
有些情况下,你甚至不能总结没有明确的转换整数和浮点数的语言(即据我所知,SML,其中,顺便说一句,参数多态的关键是克服这类问题)。
超载
double sum = 2.0 + 3.0;
String text = "The sum is" + sum;
这里的加号表示这取决于所使用的参数两回事。 显然,运营商已经超载。 这意味着它具有依赖于操作数类型的不同实现。 根据Cardelli,这是规定的加运算特设多态的一种形式。
此,当然,也适用于在类方法重载的形式(即java.lang.Math中方法min和max被重载以支持不同的原语类型)。
在其他语言
即使继承扮演的一些这些形式多态性的实现具有重要作用,当然这不是唯一的方法。 那些不是面向对象的其他语言提供其他形式的多态性。 举个例子来说,案件鸭打字像Python或即使是在像围棋,或静态类型语言的动态语言的代数数据类型,像SML,ocaml的和Scala,或语言类型类的象Haskell语言, 多方法用Clojure , 原型继承在JavaScript等
Answer 2:
特设多态>运算符重载>无传承
特设多态>方法重载>无传承
特设多态>方法覆盖>随着传承
参数多态>泛型>无传承
亚型多态性或包容多态性>多态分配>随着传承
亚型多态性或包容多态性>多态返回类型>随着传承
亚型多态性或包容多态性>多态参数类型>随着传承
胁迫多态性>加宽>有或没有传承
强制多态性>自动装箱和拆箱>无传承
强制多态性>变参>无传承
强制多态性>类型转换>无传承
Answer 3:
当然。 在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;
}
}
然后在别处:
Foo x = new A();
System.out.println(x.a())
Foo y = new B();
System.out.println(y.a())
这两个x
和y
是Foo
S中,但有不同的结果,当你调用a()
Answer 4:
静态类型
超载 - 这意味着具有同名但不同的签名是可能的了压倒一切的多种方法
class StaticPolyExample
{
void print(int s)
{
//print s
}
void print(String s)
{
//print s
}
}
动态型
压倒一切的 - 在需要继承子类,这意味着在超类中的方法将被重新定义
class Printer
{
void print(String s)
{
// prints String
}
}
class diffPrinter extends Printer
{
void print(String s)
{
// prints String differently
}
}
Answer 5:
函数重载是多态性的一种(尽管这并不是什么是真正的多态是指),它可以在不继承来实现。
如
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());
被捕方法被称为2倍,但该代码的执行的路径是不同的。
*再次,这是不是多态的真实形态。 一般真正的多态性不能没有产业就来达到的。
Answer 6:
是的,我想他们可能就想听听多态性的接口。 因此,如果有2班从相同的接口实现,那么我们就可以在我们与ExSpect的这种intervace对象的所有场所使用。 见代码从维基百科:
// 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());
}
}
}