继承,多态,抽象类,接口

本文详细阐述了Java中的继承、super关键字、重写方法、多态概念以及抽象类和接口的使用。介绍了如何通过继承实现代码复用,重写来扩展功能,多态实现灵活调用,以及抽象类和接口在设计模式中的应用。
摘要由CSDN通过智能技术生成

1、继承

继承是描述两个类的关系,如果两个类有重复的属性和方法,我们就可以使用继承的方式来实现/设计。

  1. 继承中,子类会把父类的所有方法和属性都继承下来(除了private)。
  2. 子类继承父类后,还可以拥有自己的属性和方法。
  3. java中,(原则上)只能单继承(能写出来看的)。(一个类只能有一个父亲,但是有实现多继承的方法)
  4. 所有的类都是默认继承object(隐式).
  • 继承是时刻进行的,即改变父类中的一个属性的数值,子类中继承的对应属性的数值也会改变
// 人

public class Person {

    public String name = "人";

    // 0未知,1男,2女

    public String sex = "0";

    public void eat() {

        System.out.println("吃饭");

    }
}

  

// 中国人

public class ChinesePerson extends Person {

    public String name = "中国人";

    // 生肖

    public String shengxiao;


    public void kungfu() {

        System.out.println("功夫");

    }

}

  

// 测试

public static void main(String[] args) {

    ChinesePerson chinesePerson = new ChinesePerson();

    // 子类没有定义sex属性,但是也可以使用,因为从父类继承了

    System.out.println(chinesePerson.sex); // 0

    // 子类、父类可以有同名属性

    System.out.println(chinesePerson.name); // 中国人

    // 子类可以有自己的属性

    System.out.println(chinesePerson.shengxiao); // null

  

    // 子类没有定义eat方法,但是可以使用,因为从父类继承了

    chinesePerson.eat();

    // 子类可以有自己的方法

    chinesePerson.kungfu();

}

2、super

有继承关系的时候才有super
this指调用者本身,super指父亲类

  1. 子类实例化的过程中,父类构造器先被调用,然后再调用子类的构造器(在子类构造器内部默认调用super())。
  2. 如果子类的构造器中调用了父类的有参构造方法,那么父类无参的构造器不会被调用。
  3. super()的调用要放在第一行(保证初始化的顺序)。
  4. super可以表示父类的引用,我们可以使用super和this来区分父类和子类的同名属性和方法。

// 接着知识点1的案例

// Chinese添加方法test()

public void test() {

    // 优先找当前类的name属性

    System.out.println(name); // 中国人

    // 优先找当前类的sex属性,找不到就到父类找

    System.out.println(sex); // 0

    // 使用this关键字指定获取子类还是父类的同名属性

    System.out.println(this.name); // 中国人

    System.out.println(super.name); // 人

    // 方法和属性一样

    super.eat();

}

3、重写

  1. 定义
    重写(override):也称覆盖。重写是子类对父类非static非private非final方法的实现过程进行重新编写,返回值(JDK7以后,被重写的方法返回值类型可以不同,但是必须是具有父子关系的)和形参都不能改变,且访问权限不能比父类中被重写方法的返回权限低。即外壳不变,核心重写。

**重载(overload):**同一个类中,有相同的方法名,但是参数的类型或者参数的个数不同,这两个方法就是重载。

  1. 为什么需要重写
    原有的方法无法满足新的需求,需要对这个方法进行改良来满足新的需求。子类可以根据需要,定义特定于自己的行为。既沿袭了父类的功能名称,又根据子类的需要重新实现父类方法,从而进行扩展增强。
    示例:
// 人类

public class Person {

    public String name = "人";

    // 人都会吃饭,具体怎么吃饭的不清楚,每个区域的吃饭方式都不一样

    public void eat() {

        System.out.println("吃饭");

    }

}

// 中国人

public class ChinesePerson extends Person{

    public String name = "中国人";

    // 对eat方法进行重写,延续了父类的动作,但是做了扩展,实现了具体的吃饭方式。

    @Override

    public void eat() {

        System.out.println("使用筷子吃饭");

    }

}

// 印度人

public class IndiaPerson extends Person{

    public String name = "印度人";

    @Override

    public void eat() {

        System.out.println("使用手吃饭");

    }

}

4、多态

  1. 定义
    同一个行为具有不同的表现形式。执行一段代码,Java 在运行时能根据不同的对象产生不同的结果。

  2. 前提条件

  • 子类继承父类。

  • 子类覆盖父类的方法(重写)。

  • 父类引用指向子类对象。(申请开辟一段子类的内存空间然后赋值给父类)

  1. 示例

假设场景,学校食堂排队干饭。吃饭之前要先买饭,然后吃饭。

人都会吃饭,但是不同地区的人生活习惯不一样,吃饭方式也不一样。中国人使用筷子,英国人使用刀叉,印度人使用手。

  • 封装Person类,设置方法eat()和buyFood();

    • 再分别封装三个子类ChinesePerson、EnglishPerson、IndiaPerson;

    • 子类重写eat()方法,因为每个人吃饭的方式可能不一样;

    • buyFood()不用重写,因为每个人都得排队买饭,行为是一样的。

    
    // 人
    
    public class Person {
    
        public String name = "人";
    
        // 人都会吃饭,具体怎么吃还不清楚
    
        public void eat() {
    
            System.out.println("吃饭");
    
        }
    
        public void buyFood() {
    
            System.out.println("买饭");
    
        }
    
    }
    
    
    
    // 中国人
    
    public class ChinesePerson extends Person{
    
        public String name = "中国人";
    
        // 重写父类eat方法,实现具体的吃饭方式
    
        @Override
    
        public void eat() {
    
            System.out.println(name + "用筷子吃饭");
    
        }
    
    }
    
    // 英国人
    
    public class EnglishPerson extends Person{
    
        public String name = "英国人";
    
        @Override
    
        public void eat() {
    
            System.out.println(name + "用刀叉吃饭");
    
        }
    
    }
    
    // 用手吃饭
    
    public class IndiaPerson extends Person{
    
        public String name = "印度人";
    
        @Override
    
        public void eat() {
    
            System.out.println(name + "用手吃饭");
    
        }
    
    }
    
    
    
    // main函数测试1。
    
    public static void main(String[] args) {
    
        // 子类对象赋值给父类的引用(父类类型的变量)
    
        Person person1 = new ChinesePerson();
    
        Person person2 = new IndiaPerson();
    
        // 执行的是子类的方法
    
        person1.eat(); // 中国人用筷子吃饭
    
        person2.eat(); // 印度人用手吃饭
    
    }
    
    
    
    // main函数测试2。实现食堂排队买饭场景。
    
    // 我们封装ganfan()方法,过程为 买饭 + 吃饭。
    
    public static void main(String[] args) {
    
        // 使用数组模拟排队
    
        Person[] persons = { new ChinesePerson(), new IndiaPerson(), new EnglishPerson(), new IndiaPerson() };
    
        // 循环排队干饭
    
        for(int i = 0; i < persons.length; i++) {
    
            ganfan(persons[i]); // 运行过程中才确定是什么对象
    
            System.out.println("-----------");
    
        }
    
    }
    
    // 买饭 + 吃饭
    
    // 干饭方法不需要具体知道是什么人吃饭
    
    // 通过多态,实现不同的人使用不同的吃饭方式
    
    public static void ganfan(Person person) {
    
        person.buyFood();
    
        person.eat();
    
    }
    
    

​ 注意1:多态场景下,父类引用调用的方法是子类的方法,调用的属性是父类的属性。

​ 注意2:父类引用不能调用子类独有的方法(即不是(继承||重写)父类的方法)

5、抽象类

5.1 定义

抽象类也是类,只是抽象类具备了一些特殊的性质。

我们以前编写一个类时,会为这个类编写具体的属性和方法,但有一些情况我们只知道一个类需要哪些属性方法,但不知道这些方法具体是什么,这时我们就要用到抽象类。

举个例子,有一位老师布置了一篇作文,要求以春天为题目写一篇字数不少于800字写景作文,题材不限(诗歌除外)。在这个例子中,这篇作文就是一个抽象类,这个抽象类有两个属性:以春天为题目和字数不少于800,还有一个抽象方法:写景。现在全班学生就会按照老师所给的要求,即抽象类,去完成作业。

抽象类就像一个大纲,一种规范。

抽象类体现的是一种模板式设计。以抽象类作为其子类的模板,从而避免了子类设计的随意性。

有抽象方法的前提是其所属的类是抽象类;
抽象函数与普通函数最大的区别就是它不需要有大括号,只要有声明就可以了

5.2 语法

关键字:abstract。


// 抽象类

public abstract class 类名 {

    // 抽象方法

    public abstract 返回值 方法名();

}

  1. 抽象类不能实例化,即不能创建对象,只能被继承,然后实例化。
  2. 继承抽象类的非抽象类必须实现抽象方法。
  3. 抽象类中可以没有抽象方法,有抽象方法的类一定是抽象类。
  4. 抽象类可以继承抽象类,可以不用实现抽象方法。
  5. 抽象的方法不能private,final,static修饰。

6、接口

6.1 定义

接口这个概念在生活中并不陌生,比如计算机往往有多个USB接口,可以插各种USB设备,如键盘、鼠标、U盘、摄像头、手机等。

接口声明了一组能力,但它自己并没有实现这个能力,它只是一个约定。接口涉及交互两方对象,一方需要实现这个接口,另一方使用这个接口,但双方对象并不直接互相依赖,它们只是通过接口间接交互,上面的USB接口来说,USB协议约定了USB设备需要实现的能力,每个USB设备都需要实现这些能力,计算机使用USB协议与USB设备交互,计算机和USB设备互不依赖,但可以通过USB接口相互交互。

6.2 作用

Java中是单继承的,怎么才能让类实现多继承呢?

比如燕子会飞,飞机也会飞,他们具有相同的行为,但是他们是毫不相关的两个类,如果让燕子和飞机都继承于同一个抽象类,显然不合适。而且燕子会吃东西,飞机可以加油,这时候也不适合在同一个抽象类中定义让他们继承。

接口主要解决的问题:

  1. 多继承

  2. 不同子类实现相同的行为

6.3 语法

关键字:interface


interface 接口名 {

}

  1. 接口不能实例化,需要有类使用implements来实现接口,并且实现接口的抽象方法。

  2. 接口中的方法默认是抽象的。//自带public abstract,故类也是抽象的

  3. 接口的方法不能使用private和final、static修饰。

  4. 接口可以多继承,用逗号隔开。

  5. 接口可以定义常量,常量默认会带public static final 。该常量不能修改,一般我们通过【接口名.常量】来访问。

//extends:继承类
//implements继承接口(接口与类没有区别,接口也是类的一种)
//接口只能定义常量与抽象方法,常量必须被初始化

示例:假设场景,家里的门。门都有open( )和close( )两个动作,此时我们可以通过抽象类和接口来定义这个抽象概念。


public abstract class Door {

    public abstract void open();

    public abstract void close();

}


public interface Door {

    public abstract void open();

    public abstract void close();

}

但是现在如果我们需要门具有报警alarm( )的功能,那么该如何实现?下面提供两种思路:

  1. 将这三个功能都放在抽象类里面,但是这样一来所有继承于这个抽象类的子类都具备了报警功能,但是有的门并不一定具备报警功能;

  2. 将这三个功能都放在接口里面,需要用到什么功能我们就实现什么接口。

从这里可以看出, Door的open() 、close()和alarm()根本就属于两个不同范畴内的行为,open()和close() ,而alarm()属于延伸的附加行为。因此最好的解决办法是单独将报警设计为一个接口,包含alarm()行为,Door设计为单独的一个抽象类,包含open和close两种行为。


// 接口强调行为,报警的动作

public interface Alram {

    void alarm();

}

  

// 抽象类强调事物,门具备开和关固有的行为特性

public abstract class Door {

    void open();

    void close();

}

// 如果是警报门。具备门基本的特征,所以继承Door。又具备报警的功能就实现Alarm接口进行扩展。

// 如果是普通门,把implements Alarm去掉即可。

class AlarmDoor extends Door implements Alarm {

    void oepn() {

      //....

    }

    void close() {

      //....

    }

    void alarm() {

      //....

    }

}

  

// 假如是一个火灾警报器,不具备门的特性,我们直接实现Alarm接口就好了

class FireAlarm implements Alarm {

    void alarm() {

      //....

    }

}

6.5 JDK1.8之后接口的变化

在jdk1.8之后接口可以定义static和default方法。


// 使用接口名.方法名调用

static void 方法名称() {

}
//此时这个方法属于类故不可以被继承


// 可以被子类继承,实例化子类之后调用

default void 方法名称() {

}
//子类可以选择是否继承

在1.8之前,接口与其实现类之间的耦合度太高,当需要为一个接口添加方法时,所有的实现类都必须随之修改。默认方法解决了这个问题,它可以为接口添加新的方法,而不会破坏已有的接口的实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值