2.1 继承的概述
2.1.1 生活中的继承
-
财产继承
-
绿化:前人栽树,后人乘凉
继承有延续(下一代延续上一代的基因、财富)、扩展(下一代和上一代又有所不同)的意思。
2.1.2 Java中的继承
角度一:从上而下
为描述和处理个人信息,定义类Person
为描述和处理学生信息,定义类Student
通过继承,简化Student类的定义
说明:Student类继承了父类Person的所有属性和方法,并增加了一个属性school。Person中的属性和方法,Student都可以使用。
角度二:从下而上
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类中无需再定义这些属性和行为,只需要和抽取出来的类构成继承关系
。
2.1.3 继承的好处
-
继承的出现减少了代码冗余,提高了代码的复用性。
-
继承的出现,更有利于功能的扩展。
-
继承的出现让类与类之间产生了
is-a
的关系,为多态的使用提供了前提。-
继承描述事物之间的所属关系,这种关系是:
is-a
的关系。可见,父类更通用、更一般,子类更具体。
-
注意:不要仅为了获取其他类中某个功能而去继承!
2.2 继承的语法
2.2.1 继承中的语法格式
通过 extends
关键字,可以声明一个类B继承另外一个类A,定义格式如下:
[修饰符] class 类A { ... } [修饰符] class 类B extends 类A { ... }
2.2.2 继承中的基本概念
类B,称为子类、派生类(derived class)、SubClass
类A,称为父类、超类、基类(base class)、SuperClass
2.3 代码举例
1、父类
/* * 定义动物类Animal,做为父类 */ public class Animal { // 定义name属性 String name; // 定义age属性 int age; // 定义动物的吃东西方法 public void eat() { System.out.println(age + "岁的" + name + "在吃东西"); } }
2、子类
/* * 定义猫类Cat 继承 动物类Animal */ public class Cat extends Animal { int count;//记录每只猫抓的老鼠数量 // 定义一个猫抓老鼠的方法catchMouse public void catchMouse() { count++; System.out.println("抓老鼠,已经抓了" + count + "只老鼠"); } }
3、测试类
public class TestCat { public static void main(String[] args) { // 创建一个猫类对象 Cat cat = new Cat(); // 为该猫类对象的name属性进行赋值 cat.name = "Tom"; // 为该猫类对象的age属性进行赋值 cat.age = 2; // 调用该猫继承来的eat()方法 cat.eat(); // 调用该猫的catchMouse()方法 cat.catchMouse(); cat.catchMouse(); cat.catchMouse(); } }
2.4 继承性的细节说明
1、子类会继承父类所有的实例变量和实例方法
从类的定义来看,类是一类具有相同特性的事物的抽象描述。父类是所有子类共同特征的抽象描述。而实例变量和实例方法就是事物的特征,那么父类中声明的实例变量和实例方法代表子类事物也有这个特征。
-
当子类对象被创建时,在堆中给对象申请内存时,就要看子类和父类都声明了什么实例变量,这些实例变量都要分配内存。
-
当子类对象调用方法时,编译器会先在子类模板中看该类是否有这个方法,如果没找到,会看它的父类甚至父类的父类是否声明了这个方法,遵循
从下往上
找的顺序,找到了就停止,一直到根父类都没有找到,就会报编译错误。
所以继承意味着子类的对象除了看子类的类模板还要看父类的类模板。
2、子类不能直接访问父类中私有的(private)的成员变量和方法
子类虽会继承父类私有(private)的成员变量,但子类不能对继承的私有成员变量直接进行访问,可通过继承的get/set方法进行访问。
3、在Java 中,继承的关键字用的是“extends”,即子类不是父类的子集,而是对父类的“扩展”
子类在继承父类以后,还可以定义自己特有的方法,这就可以看做是对父类功能上的扩展。
4、Java支持多层继承(继承体系)
class A{} class B extends A{} class C extends B{}
说明:
子类和父类是一种相对的概念
顶层父类是Object类。所有的类默认继承Object,作为父类。
5、一个父类可以同时拥有多个子类
class A{} class B extends A{} class D extends A{} class E extends A{}
6、Java只支持单继承,不支持多重继承
public class A{} class B extends A{} //一个类只能有一个父类,不可以有多个直接父类。 class C extends B{} //ok class C extends A,B... //error
3. 方法的重写(override/overwrite)
父类的所有方法子类都会继承,但是当某个方法被继承到子类之后,子类觉得父类原来的实现不适合于自己当前的类,该怎么办呢?子类可以对从父类中继承来的方法进行改造,我们称为方法的重写 (override、overwrite)
。也称为方法的重置
、覆盖
。
在程序执行时,子类的方法将覆盖父类的方法。
3.1 方法重写举例
比如新的手机增加来电显示头像的功能,代码如下:
public class Phone { public void sendMessage(){ System.out.println("发短信"); } public void call(){ System.out.println("打电话"); } public void showNum(){ System.out.println("来电显示号码"); } }
//SmartPhone:智能手机 public class SmartPhone extends Phone{ //重写父类的来电显示功能的方法 @Override public void showNum(){ //来电显示姓名和图片功能 System.out.println("显示来电姓名"); System.out.println("显示头像"); } //重写父类的通话功能的方法 @Override public void call() { System.out.println("语音通话 或 视频通话"); } }
public class TestOverride { public static void main(String[] args) { // 创建子类对象 SmartPhone sp = new SmartPhone(); // 调用父类继承而来的方法 sp.call(); // 调用子类重写的方法 sp.showNum(); } }
@Override使用说明:
写在方法上面,用来检测是不是满足重写方法的要求。这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。建议保留,这样编译器可以帮助我们检查格式,另外也可以让阅读源代码的程序员清晰的知道这是一个重写的方法。
3.2 方法重写的要求
-
子类重写的方法
必须
和父类被重写的方法具有相同的方法名称
、参数列表
。 -
子类重写的方法的返回值类型
不能大于
父类被重写的方法的返回值类型。(例如:Student < Person)。
注意:如果返回值类型是基本数据类型和void,那么必须是相同
-
子类重写的方法使用的访问权限
不能小于
父类被重写的方法的访问权限。(public > protected > 缺省 > private)
注意:① 父类私有方法不能重写 ② 跨包的父类缺省的方法也不能重写
-
子类方法抛出的异常不能大于父类被重写方法的异常
此外,子类与父类中同名同参数的方法必须同时声明为非static的(即为重写),或者同时声明为static的(不是重写)。因为static方法是属于类的,子类无法覆盖父类的方法。
3.3 小结:方法的重载与重写
方法的重载:方法名相同,形参列表不同。不看返回值类型。
方法的重写:见上面。
(1)同一个类中
public class TestOverload { public int max(int a, int b){ return a > b ? a : b; } public double max(double a, double b){ return a > b ? a : b; } public int max(int a, int b,int c){ return max(max(a,b),c); } }
(2)父子类中 public class TestOverloadOverride { public static void main(String[] args) { Son s = new Son(); s.method(1);//只有一个形式的method方法 Daughter d = new Daughter(); d.method(1); d.method(1,2);//有两个形式的method方法 } } class Father{ public void method(int i){ System.out.println("Father.method"); } } class Son extends Father{ public void method(int i){//重写 System.out.println("Son.method"); } } class Daughter extends Father{ public void method(int i,int j){//重载 System.out.println("Daughter.method"); } }
个人思考:
1. 继承关系:在Java中,使用关键字extends来建立继承关系,子类继承父类的成员变量和方法。这使得代码可以更容易地维护和扩展,因为可以重用已有的代码。
2. 单继承:Java是一种单继承语言,这意味着一个子类只能继承一个父类。这是为了避免多继承带来的复杂性和潜在的冲突,但Java支持多层次的继承,即一个类可以有多个子类,每个子类都可以有自己的子类,形成一个继承层次结构。
3. 访问控制:继承还涉及到访问控制,Java中有不同的访问修饰符,如public、protected、default和private,用于控制子类是否可以访问父类的成员。这有助于维护封装性和安全性。
4. 方法覆盖(Override):子类可以重写父类的方法,以满足自己的特定需求。这被称为方法覆盖,它使得多态成为可能,即不同的对象可以对同一个方法调用产生不同的行为。
5. super关键字:super关键字用于在子类中调用父类的构造函数、方法和成员变量,以便在子类中重用父类的功能或扩展它们。
6. 构造函数:子类可以有自己的构造函数,但它也可以调用父类的构造函数来初始化父类的成员变量。这可以通过super关键字实现。
7. 继承的优点:继承提供了代码重用和扩展的机会,降低了代码的复杂性。它还促进了面向对象的设计原则,如抽象、封装和多态。
8. 继承的缺点:滥用继承可能导致紧耦合的类层次结构,难以维护和理解。此外,过度的继承可能导致性能问题和不必要的代码复杂性。因此,应当谨慎使用继承,优先考虑组合和接口实现等其他设计技巧。