黑马程序员---继承

关键字:继承、super关键字、覆盖、子类实例化、final关键字、借口、模版设计模式

 

1 继承的概念

    将一些类的共性描述提取出来,单独进行描述,再让这些类与单独描述的这个类有关系即可。

    好处:

    1. 提高代码的复用性

    2. 让类与类之间产生了关系,有了这个关系才有了多态的作用。

    注意:千万不要为了获取其他类的功能,简化代码而继承,必须是类与类之间有所属关系才可以继承。判断条件,父类中的内容是否子类都应该具备。

 

2 继承的特点

    先父类(超类、基类),后子类。Java只支持单继承,不支持多继承。A类继承B类,就不能继承其他类了。因为多继承容易带来安全隐患。多个父类定义了相同功能但功能内容不同时,子类对象不确定要运行哪一个。Java改良了多继承机制,使用另一个体现来完成表示,叫“多实现”。

    Java支持多层继承,就是一个继承体系。

使用继承体系中的功能:想要使用体系,先查阅体系中父类的描述,因为父类中定义的是该体系中共性功能,通过了解共性功能就可以知道该体系的基本功能。这个体系已经可以基本使用。

具体调用时,要创建最子类的对象。原因:一是,有可能父类不能创建对象,如抽象类;二是,创建子类对象可以使用更多的功能,包括基本功能和特有功能。

查阅父类功能,创建子类对象使用功能。

 

聚集关系(包括)

聚合:例如,球队和球员。

组合:例如,手、脚是身体的一部分。

程序反应的是现实中的关系,不一定只有继承。

 

.3 super关键字

子父类出现后,类成员的特点

1. 变量

如果子类中出现非私有的同名成员变量时,子类要访问本类的变量用this,一般可以省略;子类要访问父类中的同名变量用super,不可以省略。super和this的使用几乎一致。this代表子类对象的引用;super代表父类对象的引用。同名变量的情况比较少见,没必要重新定义。

注意,即使父类的成员变量是私有的,也可以继承,只是不能对外访问而已。

使用super继承父类的成员,在堆内存中有两个同名成员,即父类的成员(包括私有的成员)和子类的成员;方法区也是如此。所以用super可以调用父类的成员。加载子类class文件时,先加载父类class文件。

class Zi extends Fu

{

       void show()

       {

              System.out.println(this.num);

       }

}

依然可以运行,子类的堆内存中有父类的num,可以用this访问,也可以用super访问,都指向子类的对象。

 

4 函数覆盖

2. 函数

当子类中出现和父类中一样的函数时,当子类对象调用该函数,会运行子类函数的内容。如同父类的函数被覆盖一样。这也是函数的另一个特性:重写(覆盖)。其实父类的方法还在内存中,只是没有运行而已。

当子类继承了父类、沿袭了父类的功能到子类中,子类虽具备该功能,但功能的内容却和父类不一致,这是没有必要定义新功能,而是使用覆盖特性,保留父类的功能定义,并重新功能的内容。重写一定是有不同的内容,否则无须重新。

开发中,决定不能修改以前的源码!利用继承来扩展程序的功能,重新父类的功能。简化代码可以用super.方法名();

注意:

1. 子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则编译失败。例如,父类方法为public,子类为默认权限,介于私有和公有之间。

权限:public > 默认 > pirvate

2. 静态只能覆盖静态,不能覆盖非静态,因为没有加载对象。很少用。

3. 父类的方法如果是私有,无法覆盖。因为不能对子类提供,子类不能沿袭这个方法,但可以使用这个方法,相当于新建了一个方法。子类能沿袭,才有覆盖的可能。

子父类中的函数,要么覆盖,要么不能重名,否则无法运行。例如,父类:int show();和子类:void show();

 

重写和重载的比较

 

重载

重写

相同

函数名称一样,内容不一样。

要点

只看同名函数的参数列表

子父类方法要完全一样,包括返回值

否则无法覆盖,也无法运行。

应用

一个类中

子父类中

权限

不影响

子类权限大于等于父类权限

 

.5 子类的实例化过程

3. 构造函数

不能覆盖,因为类名不一样。

在对子类对象进行初始化时,父类的构造函数也会进行,那是因为子类的构造函数默认第一行有一条隐式语句:super(),super()会访问父类中空参数的构造函数。而且子类中所有的构造函数默认第一行都是super()。注意括号内没有参数。因为空参数的构造函数是默认的,即使父类中不写,子类也可以使用。传什么参数,就调用与之对应的构造函数。

注意:

1. 默认的是super(),空参数的构造函数。

2. 父类中必须有空参数是构造函数,或者默认,或者自己写当父类中只有带参数的构造函数时,子类必须使用super()语句调用父类的构造函数。例如:supet(x).意味子类必须访问父类。

因为父类中的数据子类可以直接获取,所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的。所以子类在对象初始化时,要先访问父类中的构造函数。如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。例如。

class Person

{

       private String name;

       Person(String name)

       {

              this.name = name;

       }

       void show() {}

}

 

class Student extends Person

{

       private int age;

       Student(String name)

       {

              super(name);

       }

       Student(String name, int age)

       {

              this(name);

              this.age = age;

       }

       void method()

       {

              super.show();

       }    

}

注意:super语句放在子类构造函数的第一行。

 

子类的实例化过程:

子类中所有的构造函数,默认都会访问父类中空参数的构造函数。因为子类每一个构造函数内的第一行都有一句隐式super()。如果父类中没有空参数的构造函数,子类必须手动通过super语句来指定需要访问父类中;当然,子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。如果是this(),指代空参数的构造函数,包含super()。所以,要么this()要么super()。子类中,至少有一个构造函数访问父类中的构造函数。

this和super不能同时出现,因为都只能在第一行。之所以在第一行,是因为需要先做初始化动作。

 

.6 final关键字

final:最终。作为修饰符。

特点如下:

1. 可以修饰类、方法和变量

2. 被final修饰的类不可以被继承。

   继承有利有弊,弊端就是打破了封装性。所以有些类不允许继承,内部的功能不运行复写。要么直接用这个类,要么不用。为了避免被继承、被子类复写功能,用final修饰,最终类。

3. 被final修饰的方法不可以被覆盖。只能另建新方法。强制某些方法不能被覆盖,保证使用。

4. final修饰的变量是一个常量。和static不同,只能被赋值一次,即使再次赋的值一样也不行。既可以修饰成员变量,也可以修饰局部变量(函数中)。

在描述事物的时候,一些数据的出现值是固定的,这时为了增强阅读性,给这些值起个名字,方便阅读。而这个值不需要改变,所以加上final修饰,锁住这个变量。例如,final double PI = 3.14;固定数据,即使出现一次也可以用final修饰。为了方便访问,可以这样:public static final double PI = 3.14;全局常量。

常量的书写规范:所有的字母都大写,如果有多个单词组成,单词间通过“_”连接。

5. 内部类定义在类中的局部位置上时,只能访问被final修饰的局部变量。

类的修饰符有3:public、final、默认。private用来修饰成员。

 

4.7 抽象类

   当多个类中出现了相同功能(函数声明)、但功能主体不同,这时也可以进行向上抽取,只抽取功能定义,而不抽取功能主体。例如,void study()。相当于只保留一个壳,壳内的内容由子类定义。

   对于这种表面上看不懂的函数(壳),使用abstract抽象关键字,意为“看不懂”。抽象方法调用没有意义,所以必须存放在抽象类中,也用abstract修饰。不要创建抽象类的对象,没有意义。abstract只能修饰类和方法。

 

   特点:

   1. 抽象方法一定定义在抽象类中。

   2. 抽象方法和抽象类都必须被abstract关键字修饰

   3. 抽象类不可以用new创建对象,虚拟机无法编译。因为调用抽象方法没有意义。但是可以创建引用,例如,Student s。

   4. 抽象类中的方法要被使用,必须由子类复写其所有的抽象方法后,建立子类对象调用,如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。

 

    必须全部复写,只要有一个抽象方法进入子类,子类就变成了抽象类,无法使用。即使空内容复写也可以,例如:void study() {}

    抽象类由不断的分析得到,功能声明一样,但内容不一样,所以只抽取声明,不抽取功能主体。父类只定义基本的功能需求,没有具体内容。具体内容由子类定义,其实是在强迫子类定义功能的内容。

    抽象类中也可以有非抽象方法,子类使用这些方法无需复写。抽象类和普通类没有太大区别,描述事物依然如此,只是有些看不懂的内容(抽象方法),这些看不懂的内容,也是事物的功能,需要明确出现,但无法定义主体,通过抽象方法表示。

子类复写抽象方法,直接使用普通方法。凡是那些功能不确定的方法,都沿袭到子类去做,父类只提供功能声明即可。

抽象类中可以不定义抽象方法,作用仅是不让改类建立对象。使用较少。

 

    抽象类和一般类的比较

 

抽象类

一般类

相同

描述事物的方法依旧,都有一般方法。

不同

出现了看不懂的内容,即抽象方法。

无法定义主体。

有实在内容。内部方法都可以

直接使用,无需复写。

对象

无法建立,不可以实例化,但可以

建立引用。

可以建立对象。

   

    模板方法设计模式

    在定义功能时,功能的一部分是确定的,但是有一部分是不确定的,确定的部分在使用不确定的部分。可以将不确定的部分暴露出去,由子类去完成,确定部分最好用final,使子类不能覆盖。不一定是抽象的,比如有默认的操作方式。

    提高了扩展性、复用性。模板已经确定,但是具体内容不确定,由子类完成。

 

.8 接口

    格式:interface() {}

    接口的出现将“多继承”通过另一种形式现实,即“多实现”。

    可以理解为一个特殊的抽象类,当类中的方法都是抽象的,该类可以通过接口的形式来表示。接口中的方法都是没有方法体的,便于以后的覆盖。

    class用于定义类,interface用于定义接口。都产生class文件。

    接口定义时的结构特点:

    1. 接口中常见定义:常量和抽象方法

    2. 接口中的成员都有固定修饰符:

      成员常量:例如,public static final int NUM = 3;

      成员函数:例如,public abstract void show();

    接口中的成员都是public的。只要是接口内的成员,public static final abstract这些关键字自动添加,修饰符是固定的。最好写全。不能创建对象

    类与接口之间是“实现”关系,implements。父类中有非抽象内容可以直接拿来用,子类只有将接口中的内容全部实现后才能实例化,否则是抽象类。接口是不可以创建对象的,因为有抽象方法。覆盖接口中的方法必须用public,因为接口中的方法都是共有的。抽象类的权限不确定。

    接口可以被类多实现。一个类可以同时现实多个接口。也是对多继承的不支持的补偿。依然需要覆盖每个接口的方法。即使多个接口有相同名称的方法也没有问题,因为没有方法体,不会产生矛盾,子类可以全部覆盖。

    子类在继承父类的同时,还是实现多个接口。

    类之间是继承关系;类和接口之间是实现关系;接口之间是继承关系;接口之间可以多继承,但是不能有重载函数

 

    接口的特点

    1. 接口是对外暴露的规则。

    2. 接口是程序的功能扩展。体系以外的功能扩展。

    3. 接口可以用来多实现,降低了耦合性。

例如,主板上的插槽就是对外暴露的规则,符合规则的内存条、CPU等都可以插上使用,扩展了主板的功能,同时降低了CPU和主板的关系,即耦合性(紧密联系程度)只要符合就能一起工作,同一个CPU可以插在不同的主板上使用。接口类似这些插槽。模块化开发。

    接口与类之间是实现关系;类可以继承一个类的同时再实现多个接口。

    接口与接口之间是继承关系。

 

    使用思路:

    子类继承父类的全部功能;但是,有的子类需要某些功能,有的子类不需要某些功能,可以将这些功能作为接口,需要的用,不需要的不用,防止不需要的子类也带上这些功能,而且其他的子类也可以使用这些接口;如果所有的子类都需要这些功能,但是具体的内容不同,可以使用抽象类,子类自己进行覆盖,或者使用一般类,少部分的子类通过覆盖获得自己所需要的功能。

    不同体系之间,基本功能和扩展功能有不同,例如,学生和运动员。基本功能定义在类中,扩展功能定义在接口中。

     

      ----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值