持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情
继承中的特点
1、Java只支持单继承,不支持多继承。
说明:
单继承:一个子类只能有一个父类。支持
多继承:一个子类可以有多个父类。不支持
//一个类只能有一个父类,不可以有多个父类。
class C extends A{} //ok
class C extends A,B... //error
2、Java支持多重继承(继承体系)。
说明:多重继承也叫做多层次继承
class A{}
class B extends A{}
class C extends B{}
顶层父类是Object类。所有的类默认继承Object,作为父类。
继承后的特点——成员变量
学习继承:围绕 类中的成员变量 、成员函数 、 构造函数的变化。
当类之间产生了继承关系后,其中各类中的成员变量,又产生了哪些影响呢?
需求:
1、分别定义一个父类和一个子类,让子类继承父类;
2、在父类中定义一个非静态成员变量x,并赋值为3;
3、在子类中定义一个非静态成员变量y,并赋值为10,同时定义一个一般非静态函数show,在这个函数中输出父类的成员变量x和子类的成员变量y的值;
4、定义一个测试类,在这个测试类中创建子类的对象,并使用子类的对象调用子类中的函数show。
//继承中成员变量的特点:
class Fu
{
int x = 3;
Fu()
{
System.out.println("this"+this);
}
}
class Zi extends Fu
{
int y = 10;
void show()
{
System.out.println("x="+x+",y="+y);
}
Zi()
{
System.out.println("this"+this);
}
}
class ExtendsDemo3
{
public static void main(String[] args)
{
Zi z = new Zi();
z.show();
}
}
在上述程序中 Zi 类 继承 Fu 类,在测试的程序中 我们仅仅只创建了 Zi类的对象,而没有创建Fu类的对象,但是在程序运行的过程中,使用到了Fu类中的成员变量,说明在程序中一定给Fu类的成员变量开辟了空间。
当子类继承了父类,在创建子类对象的时候,堆中的子类对象中会划分出一片空间来保存父类中的成员变量。
上述代码图解分析:
注意:加载到方法区的顺序:在jvm加载子类的时候,jvm会发现子类的字节码文件里面有一个extends标识,所以jvm会先将父类加载到方法区中,然后再将子类加载到方法区中。
上述代码创建子类对象,给堆中Zi类和Fu类中的成员变量分别隐式初始化值后,创建好的对象会去调用子类的无参构造函数,在执行无参构造函数里面的代码之前,会先执行隐式三步,即调用父类中的构造函数super().
在执行父类中构造函数的时候,同样也有隐式三步,那么父类中的super(),会去调用所有类的上帝类Object类,然后第二步给父类中成员变量x显示赋值,由于没有代码块,然后jvm回到子类构造函数中继续执行隐式第二步。
即给子类中成员变量y显示初始化值,由于子类也没有构造代码块,那么jvm会开始执行子类构造函数内容。
成员变量重名
子父类中出现了同名的成员变量,如何在子类中访问父类的成员变量?
如果在子类中要访问父类中的成员变量,可以使用super关键字。在Java中super关键字主要是用来在子类中去访问父类的内容。
super有两个作用:
-
super.父类成员(变量,函数)super.x super.show()
-
super(参数); 访问父类的构造函数
需求:
1、分别定义一个父类和一个子类,让子类继承父类;
2、在父类中定义一个成员变量x,并赋值为3;
3、在子类中定义一个成员变量x,并赋值为10,同时定义一个一般非静态函数show,在这个函数中再定义一个局部变量 x并赋值为111,在show函数中先输出父类的成员变量x和子类的成员变量x的值;
4、最后在屏幕上输出父类成员变量、子类成员变量和子类局部变量的值;
4、定义一个测试类,在这个测试类中创建子类的对象,并使用子类的对象调用子类中的函数show。
//继承中子父类中出现同名的成员变量:
class Fu
{
int x = 3;
}
class Zi extends Fu
{
int x = 10;
void show()
{
//定义一个局部变量
int x = 111;
/*
如果子类和父类中的成员变量同名,怎样去访问父类中的成员?
使用super关键字
*/
//在屏幕上打印父类中成员变量和子类中的成员变量
//System.out.println("super.x="+super.x+”,x=”+x);
System.out.println("局部变量x="+x);
System.out.println("成员变量x="+this.x);
System.out.println("父类成员变量x="+super.x);
}
}
class ExtendsDemo4
{
public static void main(String[] args)
{
Zi z = new Zi();
z.show();
}
}
需要注意的是:
1.super代表的是父类的引用,也可以理解为是一个标记,标记哪个是父类。this代表的是当前对象的引用。
2.当子父类中存在一模一样的成员变量时,子类对象优先使用属于子类对象自己的成员变量,
如果想要让子类中使用父类的成员变量,需要使用关键字:super.父类成员变量名;
小贴士:Fu 类中的成员变量是非私有的,子类中可以直接访问。若Fu 类中的成员变量私有了,子类是不能直接访问的。通常编码时,我们遵循封装的原则,使用private修饰成员变量,那么如何访问父类的私有成员变量呢?可以在父类中提供公共的getXxx方法和setXxx方法。
继承后的特点—成员方法(很重要)
当类之间产生了关系,其中各类中的成员方法,又产生了哪些影响呢?
成员方法不重名
如果子类父类中出现不重名的成员方法,这时的调用是没有影响的。对象调用方法时,会先在子类中查找有没有对应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。代码如下:
class Fu {
public void show() {
System.out.println("Fu类中的show方法执行");
}
}
class Zi extends Fu {
public void show2() {
System.out.println("Zi类中的show2方法执行");
}
}
public class Demo05 {
public static void main(String[] args) {
Zi z = new Zi();
//子类中没有show方法,但是可以找到父类方法去执行
z.show();
z.show2();
}
}
成员方法重名
如果子类父类中出现重名的成员方法,则创建子类对象调用该方法的时候,子类对象会优先调用自己的方法。
代码如下:
class Fu {
public void show() {
System.out.println("Fu show");
}
}
class Zi extends Fu {
//子类重写了父类的show方法
public void show() {
System.out.println("Zi show");
}
}
public class ExtendsDemo05{
public static void main(String[] args) {
Zi z = new Zi();
// 子类中有show方法,只执行重写后的show方法
z.show(); // Zi show
}
}