我参加了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
感谢您的帮助!
答案 0 :(得分:1)
要记住选择哪种方法的规则以及原因:
贯穿你的案件:
1:a3等于a1为假
对象a3
和a1
都属于AA
类型。所选的equals
方法是equals(Object)
,继承自Object
,因为AA
不会覆盖或超载它。它们是不同的对象,因此equals
会返回false
。没有打印fun
条消息。
有趣1:真实
2:a4等于a2为真
对象a4
和a2
都是BB
类型,但引用变量的类型为AA
。编译时签名是equals(Object)
,因为这是类型AA
上唯一名为“equals”的方法。在运行时,选择了BB
,equals(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为真
对象a2
和b1
的类型为BB
,但变量a2
的类型为AA
,而变量b1
为类型为BB
。编译时签名为equals(Object)
,因为AA
不会覆盖或超载它。在运行时,选择了BB
,equals(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为真
变量b1
和b2
的类型为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 (不重载);这是多态性。在运行时不考虑参数对象的运行时类型。