继承
一.继承概述
继承是可以通过定义新的类,在已有类的基础上扩展属性和功能的一种技术.
案例:优化 猫、狗JavaBean类的设计
狗类:Dog
属性:名字 name,年龄 age
方法:看家 watchHome(),Getter and Setter
猫类:Cat
属性:名字 name,年龄 age
方法:抓老鼠 catchMouse(),Getter and Setter
普通写法:
//猫类
public class Cat {
private String name;
private int age;
public void catchMouse() {
System.out.println("猫抓老鼠");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
//狗类
public class Dog {
private String name;
private int age;
public void watchHome() {
System.out.println("狗看家");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
相同的属性,有大量重复代码
private String name;
private int age;
相同的方法,有大量重复代码
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
继承格式
继承使用 extends 关键字,让派生类扩展基类的功能。派生类也叫子类,基类也叫超类或父类
需求:使用继承优化猫狗类的设计
- 猫和狗都属于动物的一种,它们的共有属性、功能是每种动物都具备的,可将狗和猫看成是动物的扩展;
- 定义Animal动物类,并定义猫和狗的共有内容,作为动物的基础属性和功能
属性:姓名 name,年龄 age
方法:Getter and Setter
- 分别定义Dog狗类和Cat猫类,使用继承技术在Animal动物类的基础功能上扩展自己的特有功能
Dog:看家 watchHome()
Cat:抓老鼠 catchMouse()
分析:
需求:使用继承技术优化Dog和Cat类
1.思考父类是什么?(将Dog和Cat中的相同内容全部放到父类中)子类是什么?子类需要继承父类什么?
2.先定义Animal动物类,作为Dog狗类和Cat猫类的父类
3.使用extends关键字让Dog和Cat继承Animal
// Animal动物类
public class Animal {
//父类的私有内容不能直接继承(直接使用)
private String name;
private int age;
//使用方法调用
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
//猫类 继承动物类
public class Cat extends Animal{
public void catchMouse() {
System.out.println("猫抓老鼠");
}
}
//狗类 继承动物类
public class Dog extends Animal{
public void watchHome() {
System.out.println("狗看家");
}
}
//测试Dog和Cat的功能是否能够正常使用
public class Demo {
public static void main(String[] args) {
//需求:使用继承技术优化Dog和Cat类
Dog dog = new Dog();
dog.watchHome();
dog.setAge(3);
int age = dog.getAge();
dog.setName("小黄");
Cat cat = new Cat();
String name = dog.getName();
System.out.println(name);
System.out.println(age);
}
}
小结
继承技术的作用是什么?
可以使用___extends___关键字,让子类扩展父类的属性和功能
如何使用继承技术?
在__父类_____中定义子类们的共有内容,作为基础属性和功能
让___子类_____使用 extends__ 关键字,扩展父类的属性和功能
继承技术有什么好处?
可以提高代码__复用率________,减少重复的代码
拓展
什么时候使用继承呢?
- 子类和父类具备 is a 的关系
- is a 的关系:
假设A和B两个类,A是B的一种,那么A类和B类就有 is a 的关系
此时:A类 extends B类,苹果类 extends 水果,猫类 extends 动物.
继承案例练习
需求:在某个宠物店的宠物资源管理系统中,存在猫、狗角色。
猫类属性(姓名,年龄),行为(喝水,抓老鼠)
狗类属性(姓名,年龄),行为(喝水,看家)
利用继承技术,定义猫类和狗类,并实现效果:
3岁的小猫杰克,每天都抓一只老鼠当晚餐
2岁的小狗大黄,每天都趴在门口看家护院
1.先定义Animal动物类,作为父类
2.分别定义Dog狗类和Cat猫类,作为子类
3.创建子类对象,调用功能
/**
*动物类:作为父类
*/
public class Animal {
//提取子类们共有的属性和功能:共有的属性:姓名、年龄
private String name;
private int age;
//针对被私有的属性,需要提供Getter and Setter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//共有行为方法
public void drink(){
System.out.println("喝水");
}
}
/**
* 狗类:使用extends关键字,继承Animal动物类
*/
public class Dog extends Animal {
//特有功能:看家
public void watchHome() {
System.out.println(getAge() + "岁的小狗" + getName() + ",每天都趴在门口看家护院");
}
}
public class Cat extends Animal {
//特有功能:抓老鼠
public void catchMouse() {
System.out.println(getAge() + "岁的小猫" + getName() + ",每天都抓一只老鼠当晚餐");
}
}
public class Test {
public static void main(String[] args) {
//1.先定义Animal动物类,作为父类
//2.分别定义Dog狗类和Cat猫类,作为子类
//3.创建子类对象,调用功能
Dog dog = new Dog();
dog.setName("大黄");
dog.setAge(2);
Cat cat = new Cat();
cat.setName("杰克");
cat.setAge(2);
dog.watchHome();
cat.catchMouse();
}
}
继承的注意事项
- 单继承: 一个子类只能有一个父类
- 多层继承:子类可以有父类,父类也可以有父类
- 继承成员子类能从父类那直接或间接获取属性和功能
- 祖宗类:任何一个类都直接或间接的继承Object类
分析
1.Java只能单继承(一个子类有且仅有一个父类)
需求:尝试让Son类同时继承Dad类和GrandDad类
public class GrandDad {
public void drawing() {
System.out.println("绘画");
}
}
//尝试Son多继承(同时继承)Dad和GrandDaD类,代码会报错!
//public class Son extends Dad, GrandDad {
//public class Son extends Dad extends GrandDad {
2.Java虽然只能单继承,但是可以多层继承(子类继承父类,但父类也可以继续继承父类)
- 需求:尝试让Son类继承Dad类,然后让Dad类继承GrandDad类
- 创建子类Son的对象,去调用Dad类和GrandDad类的功能
//尝试让Son继承Dad
public class Son extends Dad{
}
//让Dad类继承GrandDad
public class Dad extends GrandDad {
String car = "玛莎拉蒂";
private String house = "小洋楼";
public void swim() {
System.out.println("游泳");
}
}
Son son = new Son();
System.out.println(son.car);
son.swim();
son.drawing();
System.out.println("----------------------");
3.子类可以直接或间接继承父类的成员(直接或间接的使用父类的成员变量、成员方法),父类的私有成员,子类不能直接继承,但是可以间接继承(使用super关键字)
//System.out.println(son.house);
//'house' has private access in 'i_extends.d3.Dad'
4.Java中任何一个类都直接或间接的继承Object类
,Object类提供了一个hashCode方法,可以返回对象在堆内存的十进制地址值
//需求:创建GrandDad类对象,尝试调用hashCode方法
GrandDad grandDad = new GrandDad();
int hashCode = grandDad.hashCode();
System.out.println(hashCode);
玛莎拉蒂
游泳
绘画
----------------------
356573597
三.继承关系下,成员的访问特点
目标:了解继承关系中,子类访问成员的特点
就近原则
1.成员(变量、方法)访问的特点:
- 子类有,就访问子类自己的
- 子类没有,就访问父类的
- 子、父类都没有,代码报错!
2.指定访问父类的成员: - 使用 super 访问
public class Fu {
String str = "我是父类变量";
public void show() {
System.out.println("我是父类的show方法");
}
}
public class Zi extends Fu {
String str = "我是子类变量";
public void show() {
System.out.println("我是子类的show方法");
}
public void test() {
//1.访问变量str
System.out.println(str);
//2.访问show方法
show();
**//3.指定访问父类的str属性和show方法**
System.out.println(super.str);
super.show();
}
public class Demo {
public static void main(String[] args) {
//1.需求:按要求完成Zi类中的test方法
//创建Zi类对象,调用test()方法
Zi zi = new Zi();
zi.test();
}
}
//父类
public class Father {
String field = "父类的和子类同名属性";
public void method() {
System.out.println("父类的和子类同名方法");
}
}
//子类
public class Son extends Father {
String field = "子类的和父类同名属性";
String ziField = "子类特有属性";
public void method() {
System.out.println("子类的和父类同名方法...");
}
public void use() {
String ziField = "子类局部变量";
//练习:按要求完成以下需求
//1.访问子类的field属性
System.out.println(field);
//2.访问父类的field属性
System.out.println(super.field);
//3.访问ziField属性,此时发现方法中有一个成员变量和一个成员方法同名,此时需要用 this 来表明访问的是成员变量
System.out.println(this.ziField);
//4.访问ziField局部变量
System.out.println(ziField);
//5.访问method方法
method();
//6.访问父类的method方法
super.method();
}
}
小结
- 在子类方法中访问父类成员变量、成员方法遵循什么原则?
就近原则:子类有就用子类的,子类没有就用父类的,父类没有就报错 - 如果子、父类中出现了重名的成员变量、成员方法,如何区分?
super.父类成员 … this.本类成员
四.方法重写
- 子类和父类有一模一样的方法声明,但方法体可能不一样,此时子类方法会覆盖父类的方法(这种格式称为方法重写)
目标:掌握方法重写的特点和使用场景
### 实例
需求:在不影响B类继承使用Fu类show功能的前提下,让A类执行自己特有的show功能:"A类特有的show方法"
1.在子类A中,写一个和父类Fu一模一样的show方法(子类A重写了父类Fu的show方法)
```java
public class Fu {
public void show() {
System.out.println("fu...show...");
}
}
public class B extends Fu {
}
public class A extends Fu {
public void show() {
System.out.println("A类特有的show方法");
}
}
public class Demo01 {
public static void main(String[] args) {
A a = new A();
//方法重写后,遵循就近原则
a.show();
B b = new B();
b.show();
}
}
//执行结果:
//A类特有的show方法
//fu...show...
``
方法重写的注意事项
目标:了解方法重写的注意事项
- 重写方法的名称、形参列表必须和父类相同
- 子类重写的方法返回值类型,要小于等于父类方法的返回值类型(约定:父类大于子类)
- 子类重写父类方法时,访问权限必须大于或者等于父类 (private < 缺省 < protected < public)
- 父类私有方法,子类不能重写
方法重写的校验
@Override注解,标记一个方法是重写父类方法(语法检查)
需求:让SubClass类重写SuperClass类的各个方法
public class SuperClass {
public void method1() {
System.out.println("super...public...");
}
public A method2() {
return new A();
}
protected void method3() {
System.out.println("super...protected...");
}
void method4() {
System.out.println("super...default...");
}
private void method5() {
System.out.println("super...private...");
}
}
public class SubClass extends SuperClass {
//1.重写method1方法:保持方法名称、形参列表相同
@Override
public void method1() {
//public void method1(int age) {
System.out.println("子类重写的method1");
}
//2.重写method2方法
@Override
//public Fu method2() {
//注意:子类重写父类方法,返回值类型需要小于等于父类的
public A method2() {
return new A();
}
//3.重写method3、method4、method5方法
@Override
protected void method3() {
//注意:子类重写父类方法,访问权限要大于等于父类的
//public void method3() {
//void method3() {
//private void method3() {
System.out.println("子类重写的method3");
}
@Override
void method4() {
//protected void method4() {
//public void method4() {
//private void method4() {
System.out.println("子类重写的method4");
}
//@Override
//注意:父类私有方法,子类不能重写
private void method5() {
System.out.println("子类自己的method5方法");
}
继承关系下,构造器的访问特点
目标:了解继承关系中,构造器的访问特点
特点:访问构造器时,会先默认访问父类的空参构造器
原因:在子类的构造器第一行有一句隐藏的super();
- super访问父类构造器
super(); 用来访问父类空参数构造器
super(参数); 访问父类有参数构造器
子类继承父类后构造器的访问特点是什么样的?
子类中所有的构造方法默认都会先访问父类中__空参数构造方法
子类构方法第一行默认有一句__super()________
如果不想访问父类空参数构造器,可以使用___super(参数)_________ 访问父类有参数构造器
访问本类的构造器格式是:this()、this(参数)_____________
补充: this(),super() 都只能写在构造器的第 条语句