代码流向意外重载方法

时间:2018-04-10 22:15:23

标签: java polymorphism overloading

我参加了CS课程的作业。

其中一个问题有一些类和主要方法,我被问到输出是什么以及代码通过哪种方法。

我按照代码在脑海中解决了这个问题。之后,我运行代码,看看会发生什么。发生了什么让我很惊讶。看起来对象的引用会改变JVM选择的方法。

案例2和案例4如何进入方法1但案例3如何进入方法3.我真的很想了解发生了什么。

AA级:

public class AA
{
private int _val=0;
public AA()
{
    _val = 5;
}
public AA(int val)
{
    _val = val;
}
public int getVal()
{
    return _val;
}
public void setVal(int val)
{
    _val = val;
}
public String toString()
{
    return "val ="+_val;
}
}

BB级:

public class BB extends AA
{
private String _st;

public BB()
{
    _st = "bb";
}
public BB(String st, int val)
{
    super(val);
    _st = st;
}
public String getSt()
{
    return _st;
}

// 1
public boolean equals(Object ob)
{
    if ((ob != null) && (ob instanceof BB))
    {
        if(_st.equals(((BB)ob)._st)&&(getVal() == ((BB)ob).getVal()))
        {
            System.out.println("fun 1: true");
            return true;
        }

    }
    System.out.println("fun 1: false");
    return false;
}
// 2
public boolean equals(AA ob)
{
    if ((ob != null) && (ob instanceof BB))
    {
        if (_st.equals(((BB) ob)._st)&& (getVal() == ((BB)ob).getVal()))
        {
            System.out.println("fun 2: true");
            return true;
        }
    }
    System.out.println("fun 2: false");
    return false;
}
// 3

public boolean equals(BB ob)
{
    if (ob != null)
    {
        if (_st.equals(((BB) ob)._st)&& (getVal() == ((BB)ob).getVal()))
        {
            System.out.println("fun 3: true");
            return true;
        }
    }
    System.out.println("fun 3: false");
    return false;
}
}

这是主要的:

public class Driver
{
public static void main (String[] args)
{
    AA a1 = new AA();
    AA a2 = new BB();
    AA a3 = new AA();
    AA a4 = new BB();
    BB b1 = new BB();
    BB b2 = new BB();

    //12
    System.out.println("12: a3 equals a1 is " +a3.equals(a1));
    //13
    System.out.println("13: a4 equals a2 is " + a4.equals(a2));
    //14
    System.out.println("14: a1 equals a2 is " +a1.equals(a2));
    //15
    System.out.println("15: a2 equals b1 is " +a2.equals(b1));
    //16
    System.out.println("16: b1 equals a1 is " +b1.equals(a1));
    //17
    System.out.println("17: b2 equals b1 is " +b2.equals(b1));
    //18
    System.out.println("18: b1 equals a4 is " +b1.equals(a4));
}
}

我得到的输出是:

1: a3 equals a1 is false
fun 1: true
2: a4 equals a2 is true
3: a1 equals a2 is false
fun 1: true
4: a2 equals b1 is true
fun 2: false
5: b1 equals a1 is false
fun 3: true
6: b2 equals b1 is true
fun 2: true
7: b1 equals a4 is true

感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

要记住选择哪种方法的规则以及原因:

  1. 编译期间编译器选择方法签名。
  2. 在运行时选择覆盖,具体取决于调用该方法的对象的运行时类型。
  3. 贯穿你的案件:

      

    1:a3等于a1为假

    对象a3a1都属于AA类型。所选的equals方法是equals(Object),继承自Object,因为AA不会覆盖或超载它。它们是不同的对象,因此equals会返回false。没有打印fun条消息。

      

    有趣1:真实

         

    2:a4等于a2为真

    对象a4a2都是BB类型,但引用变量的类型为AA。编译时签名是equals(Object),因为这是类型AA上唯一名为“equals”的方法。在运行时,选择了BBequals(Object)中的覆盖,因为a4指的是BB类型的对象。覆盖打印fun 1并返回true

      

    3:a1等于a2为假

    参考变量的类型均为AA,但a1表示AA个对象,而a2表示BB个对象。编译时签名为equals(Object),因为AA不会覆盖它。在运行时,equals(Object)选择Object,因为AA不会覆盖它。它们是不同的对象,因此equals会返回false。没有打印fun条消息。

      

    有趣1:真实

         

    4:a2等于b1为真

    对象a2b1的类型为BB,但变量a2的类型为AA,而变量b1为类型为BB。编译时签名为equals(Object),因为AA不会覆盖或超载它。在运行时,选择了BBequals(Object)中的覆盖,因为a2指的是BB类型的对象。覆盖打印fun 1并返回true

      

    有趣2:错误

         

    5:b1等于a1为假

    变量b1的类型为BB,指的是BB个对象。变量a1的类型为AA,指的是AA对象。编译时签名为equals(AA),因为这是编译器在equals上定义的与BB最具体的匹配。在运行时,该方法打印fun 2并返回false

      

    有趣的3:真的

         

    6:b2等于b1为真

    变量b1b2的类型为BB,它们都引用BB个对象。编译时签名为equals(BB),因为这是编译器在equals上定义的与BB最具体的匹配。在运行时,该方法打印fun 3并返回false

      

    有趣的2:真的

         

    7:b1等于a4为真

    变量b1的类型为BB,并引用BB个对象。变量a4的类型为AA,也指BB个对象。编译类型签名是equals(AA),因为这是编译器在equals上看到的与BB最具体的匹配。尽管a4确实是BB,但静态类型为AA。在运行时,该方法打印fun 2并返回true

    总结:

    选择的方法主要由编译器决定 ,由所涉及的变量类型 - 调用方法的变量,以及作为参数传递给方法的变量。在运行时唯一决定的是根据调用方法的对象的运行时类型选择 override (不重载);这是多态性。在运行时不考虑参数对象的运行时类型。