[code="java"]public class Atest {
public static void main(String[] args)
{
String a = new String("test");
String b = new String("test");
System.out.println(a.equals(b));
System.out.println(a==b);
System.out.println(((Object)a).equals((Object)b));
System.out.println(Atest.compare(a, b));
System.out.println(Atest.isStr((Object)a));
}
public static boolean compare(Object a,Object b)
{
return a.equals(b);
}
public static boolean isStr(Object a)
{
if (a instanceof String)
{
return true;
}
return false;
}
}[/code]
代码运行结果为
true
false
true
true
true
我想知道为什么后三个是true.
String向上转化为Object后,调用的如果是Ojbect.equals的话,应该是false的。
Object的equals的实现
public boolean equals(Object obj) {
return (this == obj);
}
“父类的引用可以指向子类的对象”,这是java的继承的基本语法。
String a="aa";
Object b=(Object)a;
尽管b是一个Object的引用,但是指向的确实子类String的对象a.
运行期的方法调用都是和具体的对象确切类型绑定的,调用b.equals方法其实是调用子类String的equals方法。
向上转型只会丢失部分的类型信息。但是你这个对象在内存中还是这个String。只是你对这个内存的引用是用到Object。导致你使用这个Object引用的时候只能用到Object特有的方法。(向上转型的介绍)
然后由于运行时类型信息的存在,在调用该看上去是Object的某个方法时,JAVA会确定他的真正类型,然后去调用实际类型的该方法。
String的equasl方法实际上是比较String的一个内部的char字符数组是否相等。
那么就算你的二个string对象都像上转型为Object由于运行时类型信息,equals方法依旧判断的结果是相等。
a instanceof String 这个应该判断的是真正的对象(即内存中的对象)。
1.
String a = new String("test");
String b = new String("test");
就已经明确了,a和b引用的都是String类型的对象。
String类中的equals是覆盖了Object类中的equals方法。
所以,此时调用a.equals()和b.equals()都是调用String类中的equals。
原则是先看子类中有没有equals方法,没有的话再逐级向上查找。String本身就存在equals方法,所以直接调用该方法。
2.
把a和b都强制转换为Object的话,和转换以前只有一个区别,那就是调用的方法必须在Object类中存在,否则编译的时候就报错,因为Object类中存在equals方法,所以可以顺利编译通过,但是在执行的时候,还是按照1.中的原则进行,也就是先看引用的对象本身是否存在equals方法,没有的话再逐级向父类查找,而String对象中存在equals方法,所以就直接调用String类中的equals方法。
也就是说,强制转换成Object或者通过方法调用传给一个Object的引用,只是在编译的时候有些区别,程序运行期间,方法调用的规则是一样的,只看引用的对象具体是什么类型的,如果是String就调用String中的equals。
这样做的好处是,我们可以基于一个父类定义出多个子类,然后用父类的引用接收具体的子类的对象,而实际传入的子类可以在运行期间任意指定。也就是我们常说的运行时多态。
class base{
protected hello(){}
}
class sub1 extends base{
public void hello(){System.out.println("sub1");}
public void show(){}
}
class sub2 extends base{
public void hello(){System.out.println("sub2");}
public void show(){}
}
}
void test(base b){
b.hello();
}
test(new sub1()); //sub1
test(new sub2()); //sub2
sub1 obj= new sub1();
((base)obj).show(); //编译报错,因为base中没有定义show方法
一句话:虚方法调用
有一种概念叫 override
对象在运行期始终是你new的对象。转化类型之后仍然还是那个对象。类型匹配仅仅是编译期有用,防止赋值错误。