JAVA程序员笔记 第010篇—面向对象(三)继承、多态

23 篇文章 0 订阅
20 篇文章 0 订阅

面向对象的三大特点都java基础重点中的重点,其中,继承和多态这集的知识点很多,比较难理解,不理解一定要多问,多查,多练

继承

extends 代表 继承
继承的类称为子类,被继承的类称为父类
子类可以继承并使用父类中定义的 公开的 或者 受保护的 属性和方法。

JAVA 采用单继承,既任意一个类 只有一个直接父类
JAVA中,Object 是所有类的 父类(当一个类有直接父类时,Object是间接父类)

子类调用父类:

子类的方法或构造器中,通过使用 super.属性super .方法 的方式 调用父类中声
明的属性或方法。但是,通常情况下,我们习惯省略super

特殊情况:

  • 当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的使用"super.属性"的方式,表明调用的是父类中声明的属性。
  • 当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须
    显式的使用"super.方法"的方式,表明调用的是父类中被重写的方法。
super调用构造器:

1.子类的构造器中使用 super(形参列表) 的方式,调用父类中声明的指定的构造器,且 super(形参列表) 的使用,必须声明在子类构造器的首行
2.类的构造器中,this(形参列表) 或 super(形参列表) 只能二用一,不能同时出现
3.构造器的首行,没显式的声明"this(形参列表)”或"super(形参列表)",则默认调用的是父类中空参的
构造器: super()
4.类的多个构造器中,至少一个类的构造器中使用了 super(形参列表) ,调用父类中的构造器

重点理解:

继承中类加载的问题

1.子类在创建对象时,先发生类加载,在类加载中,会先执行父类的类加载过程(参考类加载的步骤),然后才是自己的来加载过程。对象创建过程同理
2.子类的(有参,无参)构造方法,都会默认调用父类的无参构造(super(),在构造方法第一行,默认不显示)。
因此,当父类中没有无参构造方法时(因为提供了有参构造),子类的构造方法就会报错。这时需要手动调用父类的 有参构造。

举例说明:
创建Animal类
并提供有参构造方法,此时JVM 不再提供 默认的空参构造方法

@AllArgsConstructor //这是提供了有参构造,用到了之前学习的jar包知识
public class Animal {
//父类的属性
    String name;
    int age;

    //public void run(){
     //   System.out.println("动物跑");
    }
}

然后创建Dog类,继承Animal类

public class Dog extends Animal{//继承父类 Animal
    private String color;//子类自己的属性

    public Dog(String name,int age,String color){//狗的有参构造
        super(name,age);//这是调用的父类的有参构造
        this.color = color;//传入的局部变量,赋给Dog的color属性
    }
    public Dog(){
        //默认会调用父类的无参构造,但此时 父类 有有参构造了,所以不提供 无参  因此报错
    }
    public static void main(String[] args) {
        Dog dog = new Dog("大狗",2,"随便啥颜色都行");
    }
}

————————————————————————————————————————————————————
方法的重写:
知识点很简单,但后期写项目时很重要。

当 父类中, 提供的方法,不满足 子类的需求的时候
子类 可以 重写 父类的方法,这种现象称为:重写/覆盖 一般就叫重写。
方法的重写主要体现的 程序的 可扩展性

方法重写的限制:
子类能够继承的方法,才可以 重写方法

方法重写的要求
a).权限修饰符 和 父类 保持一致,或 比父类的权限更高
b).方法的返回值类型,方法名,参数列表 必须和 父类完全一致
c).异常的处理 和 父类相同 或者 比父类抛出的异常 更窄

另外,IDEA可以使用 CTRL + O 快速重写 父类中的方法

@Override 可以检查,方法是否满足 重写的要求,可加可不加,建议加上

多态

多态使用的前提:

1.类的继承关系
2.方法的重写

注意:对象的多态性 只适用于 方法 不适用于 属性

自己的理解:

多态具体体现为:父类类型 对象名 = new 子类类型(参数)
子类对象指向 父类引用,我们在用这个对象调用方法时,实际上调用的是 子类重写的父类的方法
编译看左边,运行看右边

向上转型和向下转型

多态的使用 会导致 子类对象 自动向上转型,这会导致子类的特性的丢失:

父类类型 对象名 = new 子类类型(参数)
这时 对象只能够调用父类的属性和方法,不能 调用子类特有的方法和属性,因此需要向下转型。

那这时候就有人说了:那为什么刚刚上面对象调父类方法实际却使用了子类重写后的方法呢?

注意,请记住 重写 的另一个叫法:覆盖,实际上在类加载的过程中,内存已经加载了子类的属性和方法,子类重写(覆盖)父类的方法,因此,指向父类方法的“箭头”(我自己起的名字),现在指向的是 把父类方法覆盖了的子类方法因此,实际上使用的还是 子类重写后的方法。
那么,能“重写”属性吗?很遗憾,这是不行的。
.
举个例子:
父亲切菜的方法是用刀,儿子重学(重写)了切菜的方法,他用手(别在意细节)
然后,你取一个儿子类对象 取名 小明(对象名),让小明(对象名)用从他爹那儿学来的方法切菜,他还是用手切。

instanceof与JDK-16新特性:

回到正题,显示在子类的特性 需要 向下转型,向下转型时用 强制类型转换。()

注意:向下转型有风险,比如:有一个类型 圆柱,通过多态赋给了他的父类 图形类的引用。这时将其强转成 他本身类(圆柱类)或者他的父类(圆类)是可以的。
但不能强转成除此之外的其他类。我们可以添加判断语句,配合强转

使用Instanceof关键字,使用该关键字的语句 返回值类型时boolean
语法: 对象 instanceof 某某类型

可以理解为 对象的类型 是不是 某某类型

对instanceof的优化
之前我们需要创建一个类的对象,然后再去比较,现在我们可以直接在语句里创建对象

if(a intanceof Circle b){//创建Circle类对象b,判断 某个对象a 是不是 对象b的类型
   b.test();//然后b调方法
}  

区别 转型 与 数据类型转换:
图片转载自:bilibili视频网站
up主:尚硅谷
在这里插入图片描述

后面学习的抽象类,接口 都体现了多态性(因为抽象类和接口都不能实例化,需要多态)

继承与多态例题

Animal,作为Dog和Cat的父类

父类中定义方法,子类继承父类,并重写(覆盖)方法
如果只需要用到子类的方法,父类中方法体可以不写内容。
例题中调用了父类的方法,所以随便写点啥

public class Animal {
    public void eat() {
        System.out.println("我是父类的吃方法");
    }
    public void shout() {

    }
}

狗类
子类重写方法前加上@Override 用来判断是否满足重写方法的条件

知识点回顾

回顾以下方法重写的条件:两同一不同
方法标识符相同
参数列表的参数个数不同 或者 参数列表的参数类型不同

class Dog extends Animal{
    @Override
    public void eat(){
        System.out.println("狗吃肉");
    }
    @Override
    public void shout(){
        System.out.println("汪汪汪");
    }
}

猫类

class Cat extends Animal{
    @Override
    public void eat(){
        System.out.println("猫吃鱼");
    }

    @Override
    public void shout(){
        System.out.println("喵喵喵");
    }

}

测试类
本测试类中为了掩饰多个知识点,写的相对有一些复杂。

其中这个test方法,就是根据你传入的参数的类型,来调用对应类型的对应方法
比如你传入Dog类对象,test就会调用dog类的eat方法 和 shout方法。
跟直接创建狗类对象dog,然后dog调Dog类方法一样,
只不过dog调test方法的话,test方法的作用就是 根据对象类型 调了两个方法而已

class AnimalTest{
    public static void main(String[] args) {
        //创建一个测试类对象,用调测试类自己的方法:test
        AnimalTest animal = new AnimalTest();

        animal.test(new Dog());
        animal.test(new Cat());
        animal.test(new Animal());

        //或者简单的 直接创建继承Animal类的Dog类对象,调用eat方法
         Animal dog= new Dog();//多态性的体现
         dog.eat();//狗吃肉

         //亦或者,匿名类
        new Dog().eat();//狗吃肉

    }
    //这是用来调 方法 的方法
    // 这个方法的作用,就是 根据你传入的animal类型,调用 该类型 对应的方法。
    public void test(Animal animal){//
        animal.eat();
        animal.shout();
    }
}

static补充:
static修饰的方法(也就是静态方法),没有多态,不能被重写

final补充:
final修饰的方法,不能被子类重写
final修饰的类,不能被继承

在父类里定义一个final方法
在这里插入图片描述
子类中无法重写该方法,因为他是final修饰的
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值