面向对象之继承最简单易懂篇

一、继承

继承机制:是面向对象程序设计使代码可以复用利用的重要手段,允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生的新类称为派生类

目的:代码重用,类重用

概念:父类(基类、超类),子类(派生类)

关键字:extends

继承主要解决共性抽取的问题

1. 背景

当有多个类存在一些代码有的一样,有的不一样,又希望能够进行代码重用,此时就需要通过继承来实现

未使用继承:

Animal类:
public class Animal {
    public String name;

    public void eat(String food){
        System.out.println(name + "正在吃" + food);
    }
}
Cat类:
public class Cat {
    public String name;

    public void eat(String food){
        System.out.println(name + "正在吃" + food);
    }
}
Bird类:
public class Bird {
    public String name;

    public void eat(String food){
        System.out.println(name + "正在吃" + food);
    }
}

使用继承后:

Cat类、Bird类除了继承了Animal类的属性、方法,还可以有自己的方法、属性。

Animal类:
public class Animal {
    public String name;

    public void eat(String food){
        System.out.println(name + "正在吃" + food);
    }
}
Cat类:
public class Cat extends Animal{
    public void jump(){
        System.out.println(name + "正在跳");
    }
}
Bird类:
public class Bird extends Animal{
    public void fly(){
        System.out.println(name + "正在飞");
    }
}

继承就是为了代码重用,为了把多个类之间的共同代码提取出来,放到“父类”中,然后再由各个子类分别继承这个父类,从而就可以把这些重复的代码消灭了。

2. 语法规则

  • 使用extends指定父类
  • 单继承,一个子类只能继承自一个父类(一个子类只能有一个父类,但父类也可以继承自其他,避免出错,继承层数尽量少)
  • 子类会继承父类的所有字段和方法,但private修饰的成员在子类中无法访问
  • 子类的实例中也包含父类的实例,通过super来获取父类实例的引用,通过this来获取子类实例的引用
  • 每个子类实例里面都包含一个父类实例,有几个子类实例就有几个父类实例(子类实例中包含父类实例,父类实例中包含父类属性)

当Cat继承自Animal时

  • 当父类含有一个属性,子类继承自父类时,this.name和super.name对应的是同一个属性,修改与调用都对应同一内容

  • 当子类含有与父类相同的属性时,this.name和super.name不是同一内容,此时修改this.name不会对super.name 造成影响
  • 父类子类有不同属性,只能通过super.来调用父类属性,通过this.来调用子类属性

3. 构造方法 

当子类继承自父类时,构造方法的创建会有如下方式:

每个类都有构造方法,如果不显式的创建构造方法,编译器就会给这个类自动生成一个没有参数的构造方法,以上问题是由于父类创建了一个含参构造方法,而子类未创建则报错,故需要显式创建一个含参构造函数来解决。

  • 当父类里面没有创建构造方法,就被自动生成了没有参数版本的构造方法,此时如果直接new子类实例,就会调用到刚才父类这个没有参数版本的构造方法。都不写构造方法相当于隐式创建了无参构造方法;若父类只创建了一个不含参构造方法,子类则不需要显式定义构造方法。
Animal类:
public class Animal {
    public String name;

    public void eat(String food){
        System.out.println(name + "正在吃" + food);
    }
}
Cat类:
public class Cat extends Animal{

    public void jump(){
        System.out.println(name + "正在跳");
    }
}
Bird类:
public class Bird extends Animal{

    public void fly(){
        System.out.println(name + "正在飞");
    }
}

相当于:

Animal类:
public class Animal {
    public String name;

    public Animal(){

    }

    public void eat(String food){
        System.out.println(name + "正在吃" + food);
    }
}
Cat类:
public class Cat extends Animal{
    public Cat(){

    }

    public void jump(){
        System.out.println(name + "正在跳");
    }
}
Bird类:
public class Bird extends Animal{
    public Bird(){

    }

    public void fly(){
        System.out.println(name + "正在飞");
    }
}
  • 父类里面创建了含参构造方法的时候,编译器就不会自动生成无参版本的构造方法,此时再创建子类实例时,子类就必须显式的调用父类的这个构造方法,并且进行传参,否则创建不出来父类的实例,就会编译出错
Animal类:
public class Animal {
    public String name;

    public Animal(String name) {
        this.name = name;
    }

    public void eat(String food){
        System.out.println(name + "正在吃" + food);
    }
}
Cat类:
public class Cat extends Animal{

    public Cat(String name) {
        super(name);
    }

    public void jump(){
        System.out.println(name + "正在跳");
    }
}
Bird类:
public class Bird extends Animal{


    public Bird(String name) {
        super(name);
    }

    public void fly(){
        System.out.println(name + "正在飞");
    }
}
  • 若父类创建了多个构造方法,子类在创建时就要显式的决定使用哪个构造方法,否则会报错
  • static不能修饰构造方法
  • 子类继承父类后,子类需要先构造父类。在创建子类实例的时候,先构造父类对象(执行父类构造方法的逻辑),再构造子类对象(再执行子类构造方法的逻辑),如果是显式调用父类的构造方法,那么必须把父类的构造方法放在第一行代码去执行,否则报错。

  •  父类构造方法在子类构造方法之前执行
Animal类:
public class Animal {
    public String name;

    public Animal(String name) {
        this.name = name;
        System.out.println("这是父类构造方法");
    }

    public void eat(String food){
        System.out.println(name + "正在吃" + food);
    }
}
Cat类:
public class Cat extends Animal{

    public Cat(String name) {
        super(name);
        System.out.println("这是子类构造方法");
    }

    public void jump(){
        System.out.println(name + "正在跳");
    }
}
Main类:
public class Main {
    public static void main(String[] args) {
        Cat cat = new Cat("小黑");
        cat.eat("鱼");
        cat.jump();
    }
}
-----------------------------------
运行结果:
这是父类构造方法
这是子类构造方法
小黑正在吃鱼
小黑正在跳

4.protected关键字

若把字段设为private,子类无法访问,但是设成public就违背了我们的“封装”初衷,两全其美的方法就是使用protected关键字。

  •  对于类的子类和同一个包的其他类来说,protected修饰的字段和方法是可以访问的

四种访问权限:

  • private:只能在类内部被访问 权限要求最高
  • default:包级权限,可以被同包内的其他类访问
  • protected:可以被子类访问,也可以被同包的其他类访问,还能被其他包的子类访问
  • public:可以在类外部访问     权限要求最低

类前面的public表示这个类可以被其他包使用,不加只能在包内使用

属性前面四种访问权限都可加;类前面只能加public 或不加

5. final关键字

类之间继承层数不宜过多,一般要求不超三层,若过多可考虑重构,要限制继承可使用final关键字修饰类来显式禁止继承,防止继承被滥用。

public final class Animal {

}
public class Cat extends Animal{

}
--------------------
运行结果:
Error:(3, 26) java: 无法从最终Java.Animal进行继承

二、 组合

和继承类似,组合也是一种表达类与类之间关系的方式,也能够达到代码重用的效果

与继承区别:

  • 组合(has a,拥有XXX)
  • 继承(is a,是XXX)
public class SchoolMaster {
}
public class Student {
}
public class Teacher {
}

public class School {
    public SchoolMaster SchoolMaster = new SchoolMaster();
    
    public Student student1 = new Student();
    public Student student2 = new Student();
    public Student student3 = new Student();
    public Student student4 = new Student();

    public Teacher teacher1 = new Teacher();
    public Teacher teacher2 = new Teacher();
}
//表示一个学校有:一个校长、四个学生、两个老师

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值