重要的是要理解,决定哪些成员可以被访问的是引用变量类型,而不是它所引用的对象类型。这句话的确切含义是什么?这是否限制于继承的概念?虚拟机如何处理它?
它意味着,假设你有:
Object x = "hello";
变量的类型是Object
,但它引用的对象的类型是String
。不过决定你能做什么的是变量类型,所以你不能调用
// Invalid
String y = x.toUpperCase();
编译器只知道你在调用Object
上的方法,其中不包括toUpperCase
。同样,重载的方法只会根据你所知道的进行解析:public class Superclass
{
public void foo(Object x) {}
}
public class Subclass extends Superclass
{
public void foo(String y) {}
}
...
Subclass x = new Subclass();
Superclass y = x;
x.foo("hello"); // Calls Subclass.foo(String)
y.foo("hello"); // Calls Superclass.foo(Object)
例如:
Bike b = new Bike();
Bike b2 = new MountainBke();
b.speedUp();
b2.speedUp();
b2.shiftGearUp();
shiftUp
方法。由于JVM只知道b2
是一个Bike
而不是MountainBike
,所以b2.shiftGearUp()
这一行将无法编译。((MountainBike)b2).shiftGearUp(); // This compiles and runs propperly
在Java中,base
类类型的引用可以引用child
类的对象。但是使用这样的引用,我们只能访问被继承到child
类的base
类成员,而不能访问child
类可能添加的成员。
如果你有一个类Foo
,其中有一个公共字段foo
,以及一个类Bar extends Foo
,其中有一个公共字段bar
...
Foo myRef = new Bar();
只允许访问myRef.foo
,即使对象实际上是一个Bar
。Bar myRef = new Bar();
允许访问myRef.foo
和myRef.bar
。因为引用被声明为Bar
。public class Base
{
public object BaseMethod()
{
return new String("From Base");
}
}
public class Child extends Base
{
public object BaseMethod()
{
return new String("From Child.BaseMethod (overridden)");
}
public object ChildMethod()
{
return new String("From Child.ChildMethod");
}
}
public class Test
{
public static void main(String[] args)
{
Base base = new Child();
System.out.println(base.BaseMethod()); //prints "From Child.BaseMethod (overridden)"
System.out.println(base.ChildMethod()); //Will not compile as ChildMethod as reference is of type Base, and ChildMethod is not specified.
Child child = (Child) base; //But I can cast it.
System.out.println(child.ChildMethod()); // This will work.
}
}
Animal obj=new Dog();
obj.makeSound();
在这里,编译器检查Animal类中是否声明了makeSound()方法以便进行编译。