理解继承 组合 多态


前言

代码中创建的类朱总要是抽象现实中的一些事物,有的时候客观事物之间就存在一些关联关系,那么表示成类和对象的时候也会存在一定的关联,例如有一个动物类,有一个猫类和一个狗类,这三个类存在了一定的联系,猫和狗都属于动物,他们都可以继承动物当中的一些属性从而达到代码重用的效果。

一、继承

1.继承使用背景

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


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


狗类
public class Dog {
    public String name;
    public Dog(String name){
        this.name=name;
    }
    public void eat(String food){
        System.out.println(this.name+"正在吃"+food);
    }
    public void run(){
        System.out.println(this.name+"i m running");
    }
}

测试类
public class Test {
    public static void main(String[] args) {
        Animal animal=new Animal("动物");
        animal.eat("beef");

        Cat cat=new Cat("小猫");
        cat.eat("猫粮");

        Dog dog=new Dog("小狗");
        dog.eat("狗粮");
        dog.run();
    }
}

结果:
在这里插入图片描述

  • 我们发现上面三个类都具备一个相同的eat方法,而且行为完全一致。
  • 并且他们都具备一个name属性。
  • 从逻辑上来说cat和dog都是animal的一种(is a 关系)

所以我们就可以让cat和dog继承animal类来达到代码的重用。

2.继承语法规则

class 子类 extends 父类
  • java中一个子类只能继承一个父类。
  • 子类会继承父类所有public的字段和方法
  • 对于父类的private的字段和方法,子类无法访问(但是继承了)
  • 可以使用super得到父类实例的引用。
使用继承之后新的Cat类
public class Cat extends Animal {
    public Cat(String name){
        super(name);
    }
}

使用继承之后新的Dog类
public class Dog extends Animal{

    public Dog(String name){
        super(name);
    }
    public void run(){
        System.out.println(this.name+"i m running");
    }
}

3.protected关键字

当我们把父类中的字段改为private修饰之后会出现已下结果
在这里插入图片描述
因为private修饰的变量只能在类内被访问。
但是如果我们把访问修饰符改为public又违背了我们的初衷。
这时候protectde关键字的作用便发挥了出来。

+ private:类内部访问,类外部不能访问。
+ default:类内部能访问,用一个保重的类可以访问,其他类不能访问。
+ protected:类内部能访问,子类和同一个包中的类可以访问,其他类不可以访问。
+ public:类内部和类的调用者都可以访问

在这里插入图片描述

4.final关键字

我们的继承可以实现多层继承,但是实际的开发中我们一般不希望出现三层以上的继承关系,如果继承层次太多,就要考虑代码重构了。

当我们不想让一个类被继承的时候就要用到final关键字了。

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

在这里插入图片描述
我们可以发现当使用final修饰Animal类之后,Cat继承Animal会报错
final的三种用法:

  • final修饰变量:表示该变量不可被修改。
  • final修饰方法:表示该方法不能被重写。
  • final修饰类:表示该类不能被继承。

二、组合

和继承类似。组合也是一种表达类之间关系的方式,也能达到代码重用的效果。
组合表示has a语义

   老师类
public class Teacher {
    int age ;
    String  name;
    }

学生类
public class Student {
    int age;
    String  name;
    }

他们都属于学校
public class School {
   public Student [] students;
   public Teacher [] teachars;
}

三、多态

1.什么是多态?

  • 父类引用子类对象
  • 父类和子类有同名的覆盖方法
  • 通过父类引用代用子类这个重写的方法的时候发生运行时绑定,也可以称之为多态。
public class shape {              父类
    public void draw(){
    }
}

class Cycle extends  shape{            子类继承父类
    @Override
    public  void draw(){                重写方法
        System.out.println("画了一个大圆圈");
    }
}

class Rect extends  shape{
    @Override
    public  void draw(){
        System.out.println("画了一个正方形");
    }
}

class Six extends  shape{
    @Override
    public  void draw(){
        System.out.println("画了一个666");
    }
}

2.向上转型

刚才我们有这样一行代码

  Cat cat=new Cat("猫粮");

我们可以将它改写为以下形式

public class Test {
    public static void main(String[] args) {
        Cat cat=new Cat("小猫");
        Animal cat2=cat;
        animal.eat("猫粮");
    }
}

或者这种形式

Animal cat2=new Cat("小猫");

此处的 cat2 是父类 Animal 的引用,他指向了子类 Cat 的实例 cat,这种现象我们称为向上转型。

向上转型发生的时机

  • 直接赋值
  • 作为参数传递
  • 作为方法的返回值传递。

3.动态绑定

定义:父类引用引用子类对象,同时父类引用调用同名的覆盖方法。


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

    public void eat(String food){
        System.out.println("这是父类的eat方法");
        System.out.println(this.name+"正在吃"+food);
    }
}


子类
public class Cat extends Animal {
    public Cat(String name){
        super(name);
    }
    public void eat(String food){
        System.out.println("这是子类的eat方法");
        System.out.println(this.name+"正在吃"+food);
    }
}

测试类
public class Test {
    public static void main(String[] args) {
        Animal animal = new Animal("小猫");
        Animal animal2=new Cat("小猫");
        animal.eat("饭饭");
        animal2.eat("饭饭");
    }
}

在这里插入图片描述

  • animal ,animal2都是 Animal 类型的引用,但是animal 指向的是Animal 类型的实例,
  • animal2 指向的是 Cat类型的实例。
  • animal 调用了父类的 eat 方法,animal2 调用了子类的eat方法。

在调用javap -c之后我们看到在编译的时候animal调用的确实是父类的 eat( )方法,但是在运行的时候他却调用了子类的 eat( )方法,所以我们称他为运行时多态或动态绑定

4.方法重写

例如刚才的子类eat方法,
子类实现父类的同名方法,并且参数列表完全一样的时候,这种情况称为方法重写。

方法重写的注意事项:

  • 普通方法可以被重写,但是static修饰的方法不能被重写。
  • 子类方法的访问权限不能低于父类的访问权限。
  • 重写方法用@Override注解来标注。

方法重载和方法重写的区别
在这里插入图片描述

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

3 ERROR(s)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值