抱歉,你查看的文章不存在

唠唠SE的面向对象-07——继承 原

7. 继承

人属于动物,猪属于动物,等等等……

我们先来模拟几样东西:Student类,Employee类,Person类

//人 类
class Person {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

//学生 类
class Student {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
    private int studentID;
    public int getStudentID() {
        return studentID;
    }
    public void setStudentID(int studentID) {
        this.studentID = studentID;
    }
}

//职工 类
class Employee {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
    private int id;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
}

我们发现,学生与职工本来就属于人,并且在源代码中存在大量的重复代码。

如果没有继承,类和类的关系将无法描述,就像学生与人的关系一样。。。

继承特点:

1:描述类和类之间的关系

2:降低类和类之间的重复代码

3:降低对象和对象之间的代码重复使用静态变量

4:降低类和类之间的代码重复使用

所以,我们要用一个关键字来描述继承关系:

extends:描述继承关系的关键字

学生继承人,发现学生里的“姓名”属性,在人的class里也都进行了定义。

所以我们可以写成这种形式:

class Person {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

class Student extends Person {
    private int studentID;
    public int getStudentID() {
        return studentID;
    }
    public void setStudentID(int studentID) {
        this.studentID = studentID;
    }
}

Java只支持单继承!!!

1:类名的设定,被继承的类称之为父类(基类),继承的类称之为子类

2:子类并不能继承父类中所有的成员

    2.1:父类定义完整的成员(静态成员,非静态,静态变量和静态方法)都可以通过

子类名.父类静态成员 的形式调用成功。

    2.2:所有的私有成员不能继承(private修饰的成员)

    2.3:构造方法不能被继承

3:不要为了使用继承而继承。职工和学生都有共性的成员,不要为了节省代码,让职工继承学生,那样会显得没有逻辑并且关系也就描述不过去了。。。

super关键字:

子类调用父类的属性/方法

  • super主要存在于子类方法中,用于指向子类对象中父类对象。
  • 访问父类的属性
  • 访问父类的函数
  • 访问父类的构造函数

举个栗子:圆形和矩形都属于图形类

class Graph {
    public double getPerimeter() {
        return 0; // 因为不同的图形,计算方法不一样,所以这里先摆一个空壳
    }
    
    public double getArea() {
        return 0;
    }
}

class Circle extends Graph {
    private double r;

    public double getPerimeter() {
        return Math.PI * 2 * r;
    }

    public double getArea() {
        return Math.PI * r * r;
    }
}

class Rectangle extends Graph {
    private double width, height;

    public double getPerimeter() {
        return 2 * (width + height);
    }

    public double getArea() {
        return width * height;
    }
}

这样可以很明确的看出来这三个类的关系。

Override重写(覆盖、覆写):

在继承中,子类可以定义和父类相同的名称且参数列表一致的方法,将这种方法称之为方法的重写。

1:前提:必须要有继承关系

2:特点

  • 当子类重写了父类的方法,那么子类的对象如果调用该方法,一定调用的是重写过后的方法。可以通过super进行父类的重写方法的调用。
  • 继承可以使得子类可以增强/改写父类的方法

3:细节

    3.1: 方法名必须相同

    3.2: 参数列表必须相同

    3.3: 子类重写父类的方法的时候,方法的访问权限必须大于等于父类的方法的访问权限,否则编译报错

    3.4:子类重写父类的方法的时候,返回值类型必须是父类方法的返回值类型或该返回值类型的子类,不能返回比父类更大的数据类型。

4:子类对象查找属性或方法时的顺序:

        原则:就近原则。

    如果子类的对象调用方法,默认先使用this进行查找。

    如果当前对象没有找到属性或方法,找当前对象中维护的super关键字指向的对象。

    如果还没有找到,则编译报错,找到则直接调用。

在上面的例子中,圆形和矩形的计算周长和面积的方法都各不相同,所以都需要重写Graph类。

Override与Overload的区别

1:重载(overload):

  • 1:前提:所有的重载方法必须在同一个类中
  • 2:特点:方法名相同,参数列表不同,与其他的无关(访问控制符、返回值类型)
  • 3:三个不同:参数的个数不同、顺序不同、类型不同

2:重写(override):

  • 1:前提:继承
  • 2:特点:方法名必须相同、参数列表必须相同,子类的返回值类型要等于或者小于父类的返回值(继承与多态的思想,多态要到第10节再叨叨)

final关键字放在类上,则不允许被继承。一般两种情况要用final:

1. 为了防止代码功能被重写

2. 该类没有必要进行扩展

说了这么多,最后来一个综合性的例子吧!

  1. 定义动物类,会吃饭、睡觉、叫
  2. 定义猫,继承动物类,重写吃饭、叫
  3. 定义狗,继承动物类,重写睡觉、叫
class Animal {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void eat() {
        System.out.println(name + "米西米西。。。");
    }
    public void sleep() {
        System.out.println(name + "呼呼大睡。。。");
    }
    public void say() {
        System.out.println(name + "发出叫声。。。");
    }
}

class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("阿喵" + super.getName() + "大吃一顿。。。"); // 注意这里不能直接写name,关于该内容放到第12节说明
    }

    @Override
    public void say() {
        System.out.println("阿喵" + this.getName() + "喵喵的叫。。。");
    }
}

class Dog extends Animal {
    @Override
    public void sleep() {
        System.out.println("阿汪" + super.getName() + "睡个跟猪一样。。。");
    }
    
    @Override
    public void say() {
        System.out.println("阿汪" + this.getName() + "汪汪的叫。。。");
    }
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

编辑于

LinkedBear的个人空间

0 篇文章14 人订阅

相关文章

来自专栏java学习

Java每日一练(2017/6/20)

题目要求 本期题目: (单选题) 1、若有定义:byte[]x={11,22,33,﹣66};其中0≤k≤3,则对x数组元素错误的引用是() A x[5-3...

397100
来自专栏C语言及其他语言

【编程经验】结构体的高级使用及共用体的定义和使用

结构体数组 结构体数组是一个数组,其数组的每一个元素都是结构体类型。在实际应用中,经常用结构体数组来 表示具有相同数据结构的一个群体,如一个班的学生档案,...

359110
来自专栏土豆专栏

Java面试之数据类型(一)

封装类是引用类型,基本类型在传递参数的时候都是按值传递,而封装类型是按引用传递的(其实引用也是按值传递的,但是传递的是对象的地址)

20420
来自专栏码云1024

JAVA 第二天 关键字

30370
来自专栏从流域到海域

《Java程序设计基础》 第8章手记Part 2

第八章内容 Part 2 - … - 抽象类和抽象方法 - 接口及接口的实现 - 利用接口实现类的多重继承 - 内部库和匿名类 ...

22490
来自专栏iOS技术杂谈

Java8 Lambda表达式与Stream API (一):Lambda表达式你要知道的Java8 匿名内部类、函数式接口、lambda表达式与Stream API都在这里

你要知道的Java8 匿名内部类、函数式接口、lambda表达式与Stream API都在这里 转载请注明出处 https://cloud.tencent.co...

35480
来自专栏向治洪

Koltin数据类之解构申明

所谓的解构声明就是将一个对象解构(destructure)为多个变量,也就是意味着一个解构声明会一次性创建多个变量.简单的来说,一个解构声明有两个动作: 声明了...

252100
来自专栏怀英的自我修炼

怀英漫谈9 - JS 数组

所谓的数组,就是一些数据的集合,JS中没有集合的概念,所以集合也是数组的一种。如果你Java用的多,那么这个概念就有点儿难以理解,毕竟从Java的文意来说,集合...

16830
来自专栏Java3y

归并排序就这么简单

归并排序就这么简单 从前面已经讲解了冒泡排序、选择排序、插入排序,快速排序了,本章主要讲解的是归并排序,希望大家看完能够理解并手写出归并排序快速排序的代码,然后...

66170
来自专栏移动端开发

Swift 内存管理详解

Swift内存管理: Swift 和 OC 用的都是ARC的内存管理机制,它们通过 ARC 可以很好的管理对象的回收,大部分的时候,程序猿无需关心 Swift...

26590

扫码关注云+社区

领取腾讯云代金券