谈一谈java的继承

1 继承概述

1.1 概述

为什么需要用到继承了?我们举一个例子,现在有大壮、二憨、三壮三个同学,如果我对其创建描述类,需要分别创建姓名,年龄,还有工作。按照正常的做法就是分别创建三个类。但是这样太麻烦了,而且很重复。所以有什么方法省事呢。这就需要用到继承了,首先提取一个共同的类,具有姓名,年龄和爱好。在分别创建三各类继承它。然后根据自己不同的情况重写就好了。简单来说就是对一批相似度较高的类进行抽象,讲共同的变量和方法抽出来创建一个类,然后让其他对象继承它。

1.2 继承格式

一般如下所示:

class Fu{
    
}
class Zi extends Fu{
    
}

根据上面例子可得:

class Student{
    String name;
    int age;
    public void work(String str){
        System.out.println(str);
    }
}
class Dazhuang extends Student{
    
}

这样大壮就拥有了姓名、年龄和work

1.3优缺点和说明

继承的优点

就简化了代码,提高了代码的复用性,可维护性、拓展性。

继承的缺点

也极其明显,增加了耦合性,因此在使用继承的时候,不要轻易更改原码。(哪怕原码是屎山,也不能轻易改)

说明

1.单一继承;java是不支持多继承的,也就是说一个子类只允许有一个父类。

2.多层继承;虽然不可以多继承,但是可以多层继承来实现,如下:

class D1{}
class D2 extends D1{}
class D3 extends D2{}

这样就实现了多层继承。

3.所有的继承都不能继承private的类,或者方法。这个我们下面展开讲。

2 继承详解

2.1 变量

子类继承父类之后,会自动继承父类所有的变量和方法,也可以对其进行覆盖,也可以自行扩展其他的变量和方法。

对变量继承要说三点:

第一,但是并不是在子类继承了父类之后,并不是继承父类所有的变量,它遵循上一节说明提到的不可以继承private修饰的成员变量。

第二,父类和子类一定要在同一个包之下,才能继承。

第三,对于可以继承的父类和子类来说,如果子类中出现了非私有的同名变量时,子类访问本类变量可以使用this,子类访问父类变量可以使用super。

2.2 方法

方法的继承和变量继承的三点相似。

第一,不能继承private成员方法。

第二,父类和子类必须在同一个包下,才可以继承。

第三,对于可以继承的父类和子类来说,如果子类中出现了和父类一模一样的函数时,当子类独享调用改函数时,会运行子类改函数的内容,例如:

class Person{
    String name;
    int age=18;
    public void show(){
        System.out.println("这是父类的show");
    }
}
class Dazhuang extends Person{
    public void show(){
        System.out.println("这是子类的show");
    }
}

运行之后的结果是

这是子类的show

注意:这里是子类的show覆盖(重写)了父类的show方法,但是其实也保留了父类的show方法,可以使用super调用,比如

class Person{
    String name;
    int age=18;
    public void show(){
        System.out.println("这是父类的show");
    }
}
class Dazhuang extends Person{
    public void show(){
        super.show();
        System.out.println("这是子类的show");
    }
}

这里就通过super调用父类的show方法。

运行结果是:

这是父类的show

这是子类的show

这里再插一句题外话,在java中覆盖就是重写,但是重写和重载是有区别的:

重写(覆盖):

1.子类覆盖父类,必须要保证子类权限大于等于父类的权限才可以覆盖,否则编译失败,但是还是要遵循private不能被继承。

2.静态只能覆盖静态。

重载:方法重载是一个类定于了多个方法名相同,但是他们的参数数量不同捉着类型不同胡总和次序不同。

可以告诉大家辨别重写(覆盖)的一个小技巧,重写要求子类父类的这个方法一模一样。

2.3 构造函数

首先需要声明的是构造函数时不可以被继承的。但是可以被调用。

1.当父类存在无参构造函数时,在对子类对象初始化的时候,父类的构造函数也会运行,因为子类的构造函数默认第一行有一条隐式语句super()。super()会访问父类中空参数的构造函数,而且子类所有的构造函数默认第一行都是super()。

2.当父类中没有空参数的构造函数时,子类必须手动显式写super指定要访问的构造函数。

这里在加一个题外话,大家可以想一下为什么子类一定要访问父类的构造函数?

因为父类中的非私有数据都可以被子类直接获取,所以子列对象在建立的时候,需要提前了解父类的构造函数是否对其进行了修改。

3 小练习

前面两题借用了作者:Matrix海子   

出处:http://www.cnblogs.com/dolphin0520/

1.

public class Test {
    public static void main(String[] args)  {
        new Circle();
    }
}
 
class Draw {
     
    public Draw(String type) {
        System.out.println(type+" draw constructor");
    }
}
 
class Shape {
    private Draw draw = new Draw("shape");
     
    public Shape(){
        System.out.println("shape constructor");
    }
}
 
class Circle extends Shape {
    private Draw draw = new Draw("circle");
    public Circle() {
        System.out.println("circle constructor");
    }
}

结果是

shape draw constructor
shape constructor
circle draw constructor
circle constructor

这道题目主要考察的是类继承时构造器的调用顺序和初始化顺序。要记住一点:父类的构造器调用以及初始化过程一定在子类的前面。由于Circle类的父类是Shape类,所以Shape类先进行初始化,然后再执行Shape类的构造器。接着才是对子类Circle进行初始化,最后执行Circle的构造器。

2.这个题目其实更多的和多态有关

public class Test {
    public static void main(String[] args)  {
        Shape shape = new Circle();
        System.out.println(shape.name);
        shape.printType();
        shape.printName();
    }
}
 
class Shape {
    public String name = "shape";
    public Shape(){
        System.out.println("shape constructor");
    }
    public void printType() {
        System.out.println("this is shape");
    }
    public static void printName() {
        System.out.println("shape");
    }
}
 
class Circle extends Shape {
    public String name = "circle"; 
    public Circle() {
        System.out.println("circle constructor");
    }
    public void printType() {
        System.out.println("this is circle");
    }
    public static void printName() {
        System.out.println("circle");
    }
}

结果是

shape constructor
circle constructor
shape
this is circle
shape

解释:首先前两行不用解释了,是两个构造函数;

在继续解释之前,我们还要引入隐藏这个概念;

隐藏式之父类和子类拥有相同名字的属性或者方法(方法移仓只有一种,就是父类和子类存在相同的静态方法)时,父类的同名属性或者方法在形式上不见了,实际时存在的。也就是说隐藏式针对静态方法和成员变量而言的。

对多态而言,子类对象的多态性不适用于属性,因此这里调用的name和静态方法printName()都还是父类的。

 

参考博客:

https://www.cnblogs.com/dolphin0520/p/3803432.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值