详细说明:方法重载是静态/编译时绑定,但不是多态性。将静态绑定与多态性相关联是不是正确?

Posted

技术标签:

【中文标题】详细说明:方法重载是静态/编译时绑定,但不是多态性。将静态绑定与多态性相关联是不是正确?【英文标题】:Elaboration: Method overloading is a static/compile-time binding but not polymorphism. Is it correct to correlate static binding with polymorphism?详细说明:方法重载是静态/编译时绑定,但不是多态性。将静态绑定与多态性相关联是否正确? 【发布时间】:2020-01-04 04:07:53 【问题描述】:

在我提出问题之前,让我解释一下我的理解和看法。

仅通过覆盖我们无法实现多态性,除非有向上转换。由于它只能在运行时看到,人们可能将其命名为运行时多态。 (我不反对将多态性称为运行时多态性我反对方法重载称为编译时多态 多态性

我同意方法重载是静态绑定(编译时绑定),但我看不到多态性。

根据javadoc,只有polymorphism。没有编译时或运行时多态性。

根据 javadoc 在名为Defining Methods 的部分中,它解释了方法的重载。但是编译时多态并没有什么。

据我说:

如果将多态性归入运行时多态性的范畴,那么当你改变你的JDK版本时,你只能看到“编译时多态性”:

如果您从较高的 JDK 版本切换到较低的版本,您将开始看到编译错误。相同的代码在编译时表现不同,例如:lambda 表达式、菱形运算符、switch case 中的字符串、泛型等。

让我阐述一下我的观点,我对运行时多态性和编译时多态性如何出现在博客/教程中的预测:

对话1

开发人员 1:嘿,我今天读到了多态性。如果对接口进行编码,则可以实现多态性。编写代码不是与类紧密耦合,而是通过松耦合将其写入接口,调用超类方法或接口方法实际上会根据传递的实例调用子类的方法。

开发者 2:对不起,我没听明白。

开发者 1:在运行时很简单,您将传递哪个对象实例,然后执行该实例方法。

开发者 2: 哦! 运行时间。我明白了。

开发人员 1: 是相同的代码,但在运行时传递的实例不同。

开发者 2:**运行时间!好的,我知道了。

对话2

开发者 2:嘿,昨天我遇到了开发者 1,他正在讲述一些运行时多态性。通过覆盖子类中的方法,我们可以实现它。

开发者 3: 通过重写方法实现运行时多态性?那么什么是超载呢?编译时多态?

开发者 2:您如何将重载称为编译时多态性?

开发者 3: 因为它只在编译时决定。

开发者 2: 静默!

多态接口编码最好的例子是java.sql:

java.sql.Connection conn = DriverManager.getConnection(DB_URL,USER,PASS);
java.sql.Statement stmt = conn.createStatement();
java.sql.ResultSet rs = stmt.executeQuery(sql);

根据注册的驱动程序,同一段代码的行为会有所不同。这意味着,如果我们注册 mysql 驱动程序,由于多态性,这段代码会执行 mysql 实例的方法。 IE。它执行被覆盖的方法。如果您注册了Oracle驱动程序,它适用于Oracle,等等。

在上面我们发现相同的代码表现不同。

现在任何人都可以向我展示在编译时表现不同的相同代码。或者换句话说,告诉我add(3,4) 在编译期间绑定到不同方法(其他签名方法)的方法?

According to javadoc,

Java 编程语言支持重载方法,Java 可以区分具有不同方法签名的方法。

该方法将根据匹配的签名执行。方法同名不代表多态,因为调用方法的签名不同:

问题1:如果您不更改调用方法签名,它会调用与签名匹配的方法不同的方法吗?在任何情况下它的行为都会有所不同吗?

让我们看看方法重载:

public void add(int a, int b)

    System.out.println(a+b);


public void add(int a, int b, int c)

    System.out.println(a+b+c);


public static void main(String[] args)

    add(3,4);
    add(3,4,5);

问题 1: 如果方法重载是多态,那么在上面的代码块中哪一段代码的行为不同?这里的多态性在哪里?

问题2:方法调用add(3,4);在什么场景下显示多态,除非修改为add(3,4,5)


编辑@FutureVisitor,因为该线程没有找到支持将方法重载作为一种多态性的答案(即使在提出一个月的问题之后),没有任何理由接受支持方法重载不是多态性的答案,如果我的方法重载论点中的任何答案点问题不是多态性,将被接受并支持他们的观点。

【问题讨论】:

我认为您的困惑来自这样一个事实,即 java 文档对多态性的定义与计算机科学中对多态性的定义略有不同。 java 文档似乎只将运行时多态称为“多态”,但计算机科学的定义更为笼统。 在我看来 JavDoc 是正确的。 @PraveenKumarLalasangi “编译时”和“运行时”已经是特例了,CS 玩的总是最一般的。 Java 世界观只是众多可能的世界观之一(注意,我认为 Java 有一个非常好的世界观)。 把很多东西关联起来是人类的普遍行为。这就是它导航到教科书、博客等的原因。但是在编写故事时,开发人员不应该犯任何错误,否则它将成为 QA 团队的食物。 Javadoc 避免过度解释以避免混淆。否则它可能会提到方法重载是否是多态性。 【参考方案1】:

在 Java 世界中,多态是指类之间的多态。 IE。与共同的父母一起引用可能的多个子类。在 Java 中,方法之间没有多态性。

void add(int a, int b)void add(int a, int b, int c) 在 Java 语法中是完全不同的方法。不应该是这样 - 例如,在 C++ 中,您可以将它们cast 相互转换 - 但在 Java 中却是这样。

这里要理解的关键概念是method signature。方法签名在一种语言中定义了标识单个方法的内容。 (例如,除了void add(int a, int b);,您根本不能声明int add(int a, int b); 方法——返回值不是Java 中方法签名的一部分,因此编译器会将其解释为方法重新定义。)

【讨论】:

我不确定,我回答了你想知道的一切。随时向我提出扩展建议。 您通过添加点“具有不同签名的方法是两种不同的方法”为我的论点增加了价值。【参考方案2】:

人们说

    重写是运行时多态性和 重载是编译时多态性。

两者都错了。 只有覆盖不是多态性。但是重写有助于实现多态性。如果没有向上转型,就无法实现多态性。

重载是一个概念,其中方法名称和参数签名用于将方法调用绑定到方法主体,并且只能在编译时预测。但这与多态性无关。在方法重载的情况下,没有行为变化。无论是今天编译还是一年后编译,只有在更改调用方法签名时才能发现行为变化,即,只有将代码修改为 add(3,4);add(3,4,5);,因此 方法重载不是多态性.

【讨论】:

以上是关于详细说明:方法重载是静态/编译时绑定,但不是多态性。将静态绑定与多态性相关联是不是正确?的主要内容,如果未能解决你的问题,请参考以下文章

多态总结

Java学习之多态

JavaOO 多态和抽象

构造器内部的多态行为

构造器内部的多态行为

Java多态——代码复用性