Java核心技术第五章--继承(一)

一、继承的权限与子类的特点

    继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
    继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。 
    在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的。

继承的权限

    在说继承的权限之前我们先回顾一下Java中的权限

     Java用于控制可见性的4个访问修饰符:
     1)、仅对本类可见----private
     2)、对所有类可见----public
     3)、对本包和所有子类可见----protected
     4)、对本包可见----默认,没有修饰符

图片名称

    通过上述可知继承的权限分为两种情况:
    1)、同一包中,那么子类自然的继承了其父类中不是 private 的成员变量与方法作为自己的成员变量与方法,继承的成员变量与方法的访问权限保持不变。
    2)、不同包中,那么子类的 private 和默认的访问权限的成员变量不会被继承,也就是说子类只会继承父类的 protected 和 private 访问权限的成员变量和方法作为子类的成员变量和方法。

子类对象的特点

     当用子类的构造方法创建一个子类的对象时,不仅子类中声明的成员变量被分配了内存,而且父类的成员变量也都分配了内存空间,但只将其中一部分,即子类继承的那部分成员变量,作为分配给子类对象的变量。也就是说,父类中的private成员变量尽管分配了内存空间,也不作为子类对象的变量,即子类不继承父类的私有成员变量。同样,如果子类和父类不在同包中,尽管父类的友好成员变量分配了内存空间,但台不作为子类对象的变量,即如果子类和父类不在同一包中,子类不继承父类的友好成员变量。

通过上面的讨论,我们有这样的感觉:子类创建对象时似乎浪费了一些内存,因为当用子类创建对象时,父类的成员变量也都分配了内存空间,但只将其中一部分作为分配给子类对象的变量。例如,父类中的private成员变量尽管分配了内存空间,也不作为子类对象的变量,当然它们也不是父类某个对象的变量,因为我们根本就没有使用父类创建任何对象,这部分内存似乎成了垃圾一样。但是,实际情况井非如此,我们需注意到,子类中还有一部分方法是从父类继承的,这部分方法却可以操作这部分未继承的变量。

class People {
    private int averHeight=166;
    public int getAverHeight() {
        return averHeight;
    }
}
class ChinaPeople extends People{
    int height;
    public void setHeight(int h) {
        //hetght=h+averHeight;        //非法,子类没有继承averHeight
        height=h;
    }
    public int getHeight() {
    return height;
    }
}
 public class Hello{
     public static void main(String args[]) {
         ChinaPeople zhangSan=new ChinaPeople();
         System.out.println("子类对象未继承的averHeight的值是:"+zhangSan.getAverHeight());
         zhangSan.setHeight(178);
         System.out.println("子类对象的实例变量height的值是:"+zhangSan.getHeight());
     }
 }
子类对象未继承的averHeight的值是:166
子类对象的实例变量height的值是:178

二、关于 instanceof 运算符

    instanceof运算符是Java独有的双目运算符,其左面的操作元是**对象**,右面的操作元是**类**,当左面的操作元是右面的类或其子类所创建的 对象 时,instanceof运算的结果是true,否则是false。

三、理解方法调用

下面假设要调用x.f(args),隐式函数x声明为c类的一个对象

1、编译器查看对象的声明类型和方法名,编译器将会一一列举所有c类中名为f的方法和超类中的访问属性public且名为f的方法(超类的私有方法不可访问)。
2、接下来,编译器将其看调用方法时提供的参数类型,如果在所有的为f的方法中存在一个与提供的参数类型完全匹配这个选择这个方法。这个过程被称为重载解析
如果编译器没有找到与参数类匹配的 方法,或者发现经过类型转换后有多个方法与之匹配,就会报告一个错误
如果在子类中定义了一个与超类签名相同的方法,那么子类中这个方法就覆盖了超类中的相同签名的方法
3、如果private方法,static方法,final方法或者构造器,那么编译器将可以准确的知道应该调用哪个方法,我们将这种调用方式称为静态绑定
4、采用动态绑定调用方法时,虚拟机一定要调用与x所引用对象的实际类型最合适的那个类的方法,假设x的实际类型时d,他是c类的子类,如果d类定义了方法f(string),就直接调用它;否则d类的超类中寻找f(string),以此类推
虚拟机预先为每个类创建了一个方法表,其中列出了所有方法的签名和实际调用方法。如果调用super.f(param)编译器将被隐式参数超类的方法表进行搜索

动态绑定有一个非常重要的特性:无需对现存的代码进行修改,就可以对程序进行扩展在覆盖一个方法的时候,子类方法不能低于超类方法的可见性,如果超类的方法是public,子类方法一定要声明为public

四、成员变量的隐藏和方法重写

成员变量的隐藏

1、当子类的成员变量和父类的成员变量出现同名时(变量类型可以不同),这样子类就会隐藏所继承的成员变量
2、子类继承的方法只能操作子类继承和隐藏的成员变量子类新定义的方法可以操作子类继承和子类新声明的成员变量,但无法操作子类隐藏的成员变量(若要操作需要使用super关键字操作子类隐藏的成员变量)

方法重写

子类通过重写可以隐藏已继承的方法(方法重写又称方法覆盖)
重写规则:
    1.如果子类可以继承父类的某个方法,这个子类就有权利重写这个方法。
    2.子类的方法名字,返回类型,参数类型个数都要和父类的一致才算是重写
    3.@Override
重写的目的:
    隐藏继承的方法,增加拓展功能
注意事项:
    重写父类的方法时,不允许降低方法的访问权限,但可以提高访问权限。高到低:public--->protected--->友好的--->private

五、super关键字

super代表指向父类
1、子类一旦隐藏继承的成员变量/方法,那么子类创建的对象就不再拥有该变量/方法,该变量将归关键字super所有,可以使用super来访问
2、在加载子类的时候回 super()调用父类的默认构造方法

六、final关键字

1、final 可以修饰类,成员变量,方法中局部变量
2、final 修饰的类不能被继承,不能有子类
3、final 修饰方法,那么这个方法不允许子类重写,也就是说,不允许子类隐藏可以继承的final方法老老实实继承,不许任何修改
4、final 修饰的变量,就是常量,运行期间不允许修改

七、对象的上转型对象


Animal   a;
a=new Tiger();
//或者
Animal   a;
Tiger b=new  Tiger();
a=b;

/*
*  这时就称a是对象b的上转型对象 
*/
特点:
    1、上转对象不能操作子类新增的成员变量/方法(失掉这一部分属性)
    2、上转对象可以访问子类继承或者隐藏的成员变量和继承或重写的方法

八、abstract类和abstract方法

abstract类(抽象类)

用关键字abstract修饰的类称为abstract类(抽象类)
1、abstract类(抽象类)可以有abstract方法(非abstract类不能有abstract方法),也可以没有abstract方法。
2、abstract类 不能用new运算符创建对象(即:abstract类没有实例)。继承抽象类的类必须重写抽象类的抽象方法(不能使用abstract和final修饰同一个类)
3、如果一个非抽象类继承该抽象类,必须重写父类的抽象方法(给出方法体),如果是抽象类继承抽象类则,可重写或者继承父类的abstract方法
4、抽象类可以 抽象出重要的行为标准,该标准用抽象方法来表示。   抽象类声明的对象可以成为其子类的对象的上转型对象 

abstract方法(抽象方法)

使用关键字abstract修饰的方法称为abstract方法(抽象方法)
1、对于abstract方法,只允许声明,不允许实现(没有方法体)。
2、继承抽象类的类必须重写抽象类的抽象方法,不能使用abstract和final修饰同一个方法。
3、不允许使用static修饰abstract方法,即abstract方法必须是实例方法。

猜你喜欢

转载自www.cnblogs.com/shaoyu/p/11561596.html