一、继承的概念
二、继承的特点
使用继承体系中的功能:想要使用体系,先查阅体系中父类的描述,因为父类中定义的是该体系中共性功能,通过了解共性功能就可以知道该体系的基本功能。这个体系已经可以基本使用。
具体调用时,要创建最子类的对象。原因:一是,有可能父类不能创建对象,如抽象类;二是,创建子类对象可以使用更多的功能,包括基本功能和特有功能。
查阅父类功能,创建子类对象使用功能。
聚集关系(包括)
聚合:例如,球队和球员。
组合:例如,手、脚是身体的一部分。
程序反应的是现实中的关系,不一定只有继承。
三、 super关键字
子父类出现后,类成员的特点
变量
如果子类中出现非私有的同名成员变量时,子类要访问本类的变量用this,一般可以省略;子类要访问父类中的同名变量用super,不可以省略。super和this的使用几乎一致。this代表子类对象的引用;super代表父类对象的引用。同名变量的情况比较少见,没必要重新定义。
注意,即使父类的成员变量是私有的,也可以继承,只是不能对外访问而已。
使用super继承父类的成员,在堆内存中有两个同名成员,即父类的成员(包括私有的成员)和子类的成员;方法区也是如此。所以用super可以调用父类的成员。加载子类class文件时,先加载父类class文件。
class Zi extends Fu
{
void show()
{
System.out.println(this.num);
}
}
依然可以运行,子类的堆内存中有父类的num,可以用this访问,也可以用super访问,都指向子类的对象。
四、函数覆盖
函数
当子类中出现和父类中一样的函数时,当子类对象调用该函数,会运行子类函数的内容。如同父类的函数被覆盖一样。这也是函数的另一个特性:重写(覆盖)。其实父类的方法还在内存中,只是没有运行而已。
当子类继承了父类、沿袭了父类的功能到子类中,子类虽具备该功能,但功能的内容却和父类不一致,这是没有必要定义新功能,而是使用覆盖特性,保留父类的功能定义,并重新功能的内容。重写一定是有不同的内容,否则无须重新。
开发中,决定不能修改以前的源码!利用继承来扩展程序的功能,重新父类的功能。简化代码可以用super.方法名();。
注意:
1. 子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则编译失败。例如,父类方法为public,子类为默认权限,介于私有和公有之间。
权限:public > 默认 > pirvate
2. 静态只能覆盖静态,不能覆盖非静态,因为没有加载对象。很少用。
3. 父类的方法如果是私有,无法覆盖。因为不能对子类提供,子类不能沿袭这个方法,但可以使用这个方法,相当于新建了一个方法。子类能沿袭,才有覆盖的可能。
4. 子父类中的函数,要么覆盖,要么不能重名,否则无法运行。例如,父类:int show();和子类:void show();
重写和重载的比较
| 重载 | 重写 |
相同 | 函数名称一样,内容不一样。 | |
要点 | 只看同名函数的参数列表 | 子父类方法要完全一样,包括返回值 否则无法覆盖,也无法运行。 |
应用 | 一个类中 | 子父类中 |
权限 | 不影响 | 子类权限大于等于父类权限 |
五、子类的实例化过程
构造函数
不能覆盖,因为类名不一样。
在对子类对象进行初始化时,父类的构造函数也会进行,那是因为子类的构造函数默认第一行有一条隐式语句: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不能同时出现,因为都只能在第一行。之所以在第一行,是因为需要先做初始化动作。
六、 final关键字
final:最终。作为修饰符。
特点如下:
1. 可以修饰类、方法和变量。
2. 被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用来修饰成员。
七、 抽象类
子类复写抽象方法,直接使用普通方法。凡是那些功能不确定的方法,都沿袭到子类去做,父类只提供功能声明即可。
抽象类中可以不定义抽象方法,作用仅是不让改类建立对象。使用较少。
| 抽象类 | 一般类 |
相同 | 描述事物的方法依旧,都有一般方法。 | |
不同 | 出现了看不懂的内容,即抽象方法。 无法定义主体。 | 有实在内容。内部方法都可以 直接使用,无需复写。 |
对象 | 无法建立,不可以实例化,但可以 建立引用。 | 可以建立对象。 |
八、接口
例如,主板上的插槽就是对外暴露的规则,符合规则的内存条、CPU等都可以插上使用,扩展了主板的功能,同时降低了CPU和主板的关系,即耦合性(紧密联系程度)只要符合就能一起工作,同一个CPU可以插在不同的主板上使用。接口类似这些插槽。模块化开发。