首页 > 代码库 > 黑马程序员-继承
黑马程序员-继承
类用于描述事物。
父类的由来,子类不断向上抽取。
继承:
1.提高了代码的复用性。
2.让类与类之间产生了关系,有了这个关系,才有了多态的特性。
注意:不要为了获取其他类的功能,简化代码而继承。
必须是类与类之间有所属关系才可以继承。所属关系is a.
java不支持多继承。多继承带来隐患;当多个类中定义了相同的功能(如一个方法)时,当功能内容不同时,子类不确定要运行哪个。但是支持多实现。但是接口可以多继承。
java支持多层继承。也就是一个体系。A extends B C extends A
问题:继承体系在具体调用时,要创建最子类的对象,为什么?
1.父类可能不能创建对象。
2.创建子类对象可以使用更多的功能,包括基本的和特有的。
体系结构:
简单一句话:查阅父类功能,创建子类对象使用功能
继承的弊端:打破了封装性。
子父类出现后,类成员的特点:
类中成员;
1,变量 2,函数 3,构造函数
如果子类中出现非私有的同名成员变量时,子类要访问本类中的变量,用this,
子类要访问父类中的同名变量,用super.
super的使用和this的使用几乎一致。
this代表的是本类对象的引用,super代表的是父类对象的引用。
this,super存在非静态方法区。
子父类在内存:new zi分配两个属性空间:一个空间存放zi-num,一个空间存放 fu-num(即使是private,仍存在,只是访问有权限),子父类的.class文件加载:fu.class先加载,zi.class后加载。
方法区:fu:存放方法show(); zi:存放的是haha()【注意没有show】,但是有this,super引用。super.show(),
即可访问父类方法。
class fu{
int num=4;
void show(){}
}
class zi extends fu{
//子类没有num时,两种理解方式:1.num是子的属性,省略this 2.this,super指向同一num;
void haha(){
System.out.println(num);
}}
当子类继承父类,功能相同,内容不同时,使用覆盖,保留父类的功能,但是改变的父类的内容。
重载;只看同名函数的参数类型。
子类覆盖父类要遵循“两同两小一大”
“两同”即方法名相同,形参列表相同
“两小”指的是子类方法返回值类型应比父类方法返回值类型更小或相等,子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相等
“一大”指的是子类方法的访问权限应比父类方法的访问权限更大或相等。
注意:覆盖方法和被覆盖方法要么都是类方法,要么都是实例方法,不能一个是类方法一个是实例方法,
否则编译出错,静态只能覆盖静态。
override 和 overload的区别:
两者都是多态的表现形式。override是子类与父类的多态性,对父类的函数进行重新定义。overload是一个类中的多态表现。
override的复写要遵循“两同”,“两小”和“一大”。
3.子父类中的构造函数
在对子父类对象进行初始化时,父类构造函数也会运行,那是因为子类
的构造函数默认第一行有一条隐式的语句super();
super();会访问父类中的空参数的构造函数。
而且子类中所有的构造函数的第一行默认都是super();
如果父类的构造函数有参数,子类的构造函数要手动调用父类构造函数,super(x)
构造函数:用super 一般函数:用super.(多了一个点)
问题:为什么子类函数一定要访问父类函数。
因为父类中的数据,子类可以直接获取。所以子类对象在建立时,需要查看父类是
怎样初始化这些数据的(如果父类num=60,那么子类在定义num=60,无意义)。
所以要访问父类中指定的构造函数,可以通过手动定义super()语句来实现。
问题:supe语句一定要在子类构造函数的第一行。为了先初始化父类,再初始化子类,如果不
放在第一行,相当于先初始化子类(调用this),再初始化父类,那么父类岂不是
把子类给覆盖了。不可以。
结论;
子类的【所有的构造函数】,默认都会访问父类中的【空参数的构造函数】(不是默认构造函数)
因为子类每一个构造函数内的第一行都有一句隐式的super();
当父类中没有空参数的构造函数时,子类必须手动指定super语句来访问父类中的构造函数。
当然;子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。
子类中至少会有一个构造函数会访问父类中的构造函数。
注:
1.为什么super,和this不能再同一个构造函数中,必须要放在第一行。
2.为什么要放在第一行:初始化动作先执行。
练习1;
class fu{
fu(){
System.out.println("fu run");
}}
class zi extends fu {
zi(){
//super(); 在子类中隐藏了
System.out.println("zi run");
}
zi(int x){
this();//不会再有super(),有岂不是要放在第二行了,那么要如何访问父类呢,先调用本类无参gahs,在通过它,调用父类的。
System.out.println("zi....+4");
}}
练习2;
class fu{
fu(String str){
System.out.println("haha");
}}
/*
class fu{
fu(){
System.out.println("fu run");
}}
*/
class zi extends fu {
zi(){
super("haha");//不管构造方法是否调用(现在不用以后可能会用,说以有可能出错,java不允许),
//父类没有无参构造函数,子类都要手动调用,
//因为如果不手动,会默认super(),但是父类没有无参构造函数,报错。
//super(); 任何一个子类中都隐藏了super,除非手动写上this.
System.out.println("zi run");
}
zi(int x){
super("hahaa");
//this();//有this,不会再有super(),有岂不是要放在第二行了,那么要如何访问父类呢,
//先调用本类无参gahs,在通过它,调用父类的。但是this()不是隐士的,隐士的是super();
//如果不指定,它不会访问子类的的无参构造函数。
System.out.println("zi....+4");
}
}
子父类小练习1:
class Super{
int i=0;
public Super() {
System.out.println("B");
i+=2;
System.out.println(i+"...");//i=2
}}
class Demo3 extends Super{
public Demo3(String a){
System.out.println("C");
i+=5;
}
public static void main(String[] args) {
int i=4;
Super d=new Demo3("A");
System.out.println(d.i);
}}
字父类小练习2:
class fu1{
final int x= 3;
public final void show(){//final修饰的方法可以被继承。
System.out.println(x);//x变量有一个super
}
}
class zi1 extends fu1{
public final int x =4;
}
class Demo4 {
public static void main(String[] args) {
zi1 z= new zi1();
z.show();
System.out.println(z.x);
}
}