java 继承的特点

255 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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类的成员变量开辟了空间。

当子类继承了父类,在创建子类对象的时候,堆中的子类对象中会划分出一片空间来保存父类中的成员变量。

上述代码图解分析:

继承中成员变量特点.jpg

注意:加载到方法区的顺序:在jvm加载子类的时候,jvm会发现子类的字节码文件里面有一个extends标识,所以jvm会先将父类加载到方法区中,然后再将子类加载到方法区中。

上述代码创建子类对象,给堆中Zi类和Fu类中的成员变量分别隐式初始化值后,创建好的对象会去调用子类的无参构造函数,在执行无参构造函数里面的代码之前,会先执行隐式三步,即调用父类中的构造函数super().

在执行父类中构造函数的时候,同样也有隐式三步,那么父类中的super(),会去调用所有类的上帝类Object类,然后第二步给父类中成员变量x显示赋值,由于没有代码块,然后jvm回到子类构造函数中继续执行隐式第二步。

即给子类中成员变量y显示初始化值,由于子类也没有构造代码块,那么jvm会开始执行子类构造函数内容。

成员变量重名

子父类中出现了同名的成员变量,如何在子类中访问父类的成员变量?

如果在子类中要访问父类中的成员变量,可以使用super关键字。在Java中super关键字主要是用来在子类中去访问父类的内容。

super有两个作用:

  1. super.父类成员(变量,函数)super.x  super.show()

  2. 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
    }
}