JAVA面向对象的三个基本特征:封装、继承、多态。
一、向上转型
对象既可以作为它本身的类型使用,也可以作为它的基类型使用。而这种把对某个对象的引用视为对其基类型的引用的做法被称作向上转型。
package extendsTest;
public class People{
public static void eat(Fruits f){
f.appearance();
}
public static void main(String[] args) {
eat(new Apple());
}
}
class Fruits {
public void appearance(){
System.out.println("Fruits appearance()");
}
}
class Apple extends Fruits{
public void appearance(){
System.out.println("Apple appearance()");
}
}
//output:Apple appearance()
这样,我们可以看出,当我们给Fruits类添加一个新的导出类时,People类的eat方法无需更改即可以正常运行,因为eat方法仅接受基类作为参数。也就是说我们可以不用考虑导出类的存在,只和基类打交道。
进一步深入,当eat方法接受了一个Fruits的引用,编译器并不知道这个Fruits的引用是指向Apple对象,还是其它对象。
方法调用绑定,将一个方法调用同一个方法的主体关联起来被称作绑定。若在程序执行前绑定,叫做前期绑定。上述程序之所以令人迷惑,主要是因为前期绑定。因为,当编译器只有一个Fruits的引用时,它无法知道究竟调用哪个方法才对。
解决办法是后期绑定,它的含义就是在运行时根据对象的类型进行绑定。后期绑定也叫做动态绑定和运行时绑定。如果一种语言想实现后期绑定,就必须具有某种机制,以便在运行时能判断对象的类型,从而调用恰当的方法。也就是说,编译器一直不知道对象的类型,但是方法调用机制能找到正确的方法体,并加以调用。后期绑定机制随编程语言的不同而有所不同,但是只要想一下就会得知,不管怎样都必须在对象中安置某种“类型信息”。
java中除了static和final方法(private方法属于final方法)之外,其它所有方法都是后期绑定。这意味着通常情况下,我们不必判定是否应该进行后期绑定,它会自动发生。
final方法不仅可以防止其他人覆盖该方法,还可以有效地“关闭”动态绑定,或者说,告诉编译器不需要对其进行动态绑定。这样,编译器就可以为final方法调用生成更有效的代码。然后,大多数情况下,这样做对程序的整体性能不会有什么改观。所以,最好根据设计来决定是否使用final,而不是出于试图提高性能的目的来使用final。
二、私有方法不能覆盖
package extendsTest;
public class Fruits {
private void tt(){
System.out.println("Fruits tt()");
}
public static void main(String[] args) {
Fruits f=new Orange();
f.tt();
}
}
class Orange extends Fruits{
public void tt(){
System.out.println("Orange tt()");
}
}
//output:Fruits tt()
private 方法被自动认为是final的,而且对导出类是屏蔽的。因此,在这种情况下,导出类的tt()方法就是一个全新的方法,所以也就不能被重载。
结论:只有非private 方法才可以被覆盖,但还是要注意覆盖private 方法的现象,这时编译器虽然不会报错,但也不会按照我们的期望来执行。所以在导出类中,对于基类的private方法,最好采用不同的名称。
三、域和静态方法,不能覆盖
1、域
pac1kage extendsTest;
public class EatFood {
public static void getFoods(Foods f){
System.out.println(f.a);
System.out.println(f.getField());
}
public static void main(String[] args) {
getFoods(new Chicken());
}
}
class Foods{
public int a=2;
public int getField(){
return this.a;
}
}
class Chicken extends Foods{
public int a=3;
public int getField(){
return this.a;
}
}
//output:2
3
2、静态方法
package extendsTest;
public class staticTest{
public static void main(String[] args) {
Fruits f=new Orange();
f.f();
f.f2();
}
}
class Fruits {
public static void f(){
System.out.println("static Fruits f()");
}
public void f2(){
System.out.println("Fruits f2()");
}
}
class Orange extends Fruits{
public static void f(){
System.out.println("static Orange f()");
}
public void f2(){
System.out.println("Orange f2()");
}
}
//output:static Fruits f()
Orange f2()