继承
面向对象主要特征
- 继承(inheritance):
- 也称泛化,继承性是子类自动共享父类属性和方法的机制,在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并加入自己若干新的内容
- 继承简化了人们对事物的认识和描述,有益于软件复用,是OO技术提高软件开发效率的重要原因之一
- 是类之间的一种关系,一般类与特殊类之间的关系
- 封装(encapsulation):
- 所谓封装是把对象的属性和行为结合在一个独立的系统单位内部
- 尽可能隐蔽对象的内部细节,只向外部提供接口
- 封装的重要意义:
- 使对象能够集中而完整地描述并对应一个具体事物
- 体现了事物的相对独立性,使对象外部不能随意存取对象的内部数据
- 多态(polymorphism):
- 指同一个命名可具有不同的语义
- OO方法中,常指在一般类中定义的属性或方法被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为
继承的含义
- 在Java中定义一个类时,让该类通过关键字extends继承一个已有的类,这就是类的继承(泛化)。
- 被继承的类称为父类(超类,基类),新的类称为子类(派生类)。
- 子类继承父类的所有属性和方法,同时也可以增加自己的属性和方法。
继承的语法
例如
继承的规则
- Java中只支持单继承,也就是说每个类只能有 一个父类,不允许有多重继承
- 一个父类可以有多个子类
- 子类继承父类所有的属性和方法
类的继承
- 子类实例化的过程子类实例化时先实例化其父类,然后实例化子类。
- 要先调用父类的构造器,父类构造器运行完毕,才调用子类的构造器。
- 例如实例化类D,A->C->D。
- 子类实例化的过程
- 使用默认的构造器
- 在子类中的创建构造器
- 在子类中创建构造器时,必须调用父类的构造器
- 子类可以在自己的构造器中使用super关键字来调用父类的构造器
* 如果使用super关键字调用父类构造器,必须写在该子类构造器的第一行
* 如调用的是父类中无参的构造器,则可以不写super( )
* 如果子类中调用了父类无参的构造器,而父类中没有无参构造器则系统编译出错
调用构造方法
在构造方法中,可以使用this或super调用其他的构造方法
- super()
- 作用:调用父类的构造器
- 只能出现在子类的构造器中,且必须是第一行
- super()中的参数,决定了调用父类哪个构造器
- 如果子类构造器中没有出现super,那么编译器会默认加上super(),即调用父类的空构造器,如果父类没有空构造器,编译器提示错误。
- this()
- 作用:调用本类的构造器
- 只能写在构造器的第一行
- 在同一个构造器中super()和this()不能同时出现
抽象类和接口
方法覆盖
还可以称为重写(rewrite),是对从父类中继承来的方法进行改造,只有在子类继承父类时发生。
方法覆盖的规则
在子类中的覆盖方法与父类中被覆盖的方法应具有
- 相同的方法名
- 相同的参数列表(参数数量、参数类型、参数顺序都要相同)
- 相同的返回值类型
- 子类覆盖方法的访问权限要不小于父类中被覆盖方法的访问权限
在重写方法上,可以使用@Override注解来标明是重写方法
@Override表示重写(也可以省略):编译器验证@Override下面的方法名是否是父类中所有的,如果没有则报错。
Final关键字
final关键字
- final可以修饰的元素:
- 类:不能被继承
- 变量(属性和局部变量):不能被重新赋值
在声明时赋值,或在构造器中赋值
系统不会对final属性默认的赋初始值 - 方法:不能在子类中被覆盖,即不能修改。
抽象类
在Java中使用abstract关键字定义抽象类
- 抽象类声明格式
抽象类是抽象方法和非抽象方法的集合,包含特殊情况如下:
- 抽象类中可以全部是抽象方法
- 抽象类中可以全部为非抽象方法
抽象类的规则
- 抽象类不能被实例化;
- 包含的抽象方法必须在其子类中被实现,否则子类只能声明为abstract;
- 抽象方法不能为static;
在下列情况下,一个类必须声明为抽象类:
- 当一个类的一个或多个方法是抽象方法时;
- 当类是一个抽象类的子类,并且没有实现父类的所有抽象方法,即只实现部分;
- 当一个类实现一个接口,并且不能为全部抽象方法都提供实现时;
接口(interface)
-
接口的意义
- Java继承时一个类只有一个直接父类,也就是单继承,但是一个类可以实现多个接口,接口弥补了类的不能多继承缺点,继承和接口的双重设计既保持了类的数据安全也变相实现了多继承。 接口的概念
- 接口中只包含常量和抽象方法,而没有变量和方法的实现接口对类来说是一套规范,是一套行为协议;接口不是一个类,不能实例化 语法格式
- 接口的成员:抽象方法 注意
-
接口不是一个类,没有构造器,不能被实例化
接口使用interface关键字来定义,而不是class
接口 默认:
抽象方法: public abstract
类和接口的关系
类实现接口 — implements
- 为了使用一个接口,你要编写实现接口的类
- 如果一个类要实现一个接口,那么这个类就必须实现接口中所有抽象方法。否则这个类只能声明为抽象类
- 多个无关的类可以实现一个接口,一个类可以实现多个无关的接口
- 一个类可以在继承一个父类的同时,实现一个或多个接口
多态
向上转型(Upcasting)— 子类转换为父类,自动转换;
- 前提 — 具有继承或实现关系
- 向上转换损失了子类新扩展的属性和方法,仅可以使用从父类中继承的属性和方法
示例:
// 引用类型向上转型
// 子类对象赋值给父类变量
// 实现类对象赋值给接口变量
// 向上转型之后只能调用父类定义的方法 或 接口定义的方法
简单来说,多态是具有表现多种形态的能力的特征
同一个实现接口,使用不同的实现类而执行不同操作
- 多态(动态绑定、Polymorphism )
- 不同的对象对同一行为作出的不同响应
- 多态存在的三个必要条件
- 要有继承,或实现
- 要有重写
- 向上转型
- 一旦满足以上3个条件,当调用父类中被重写的方法后,运行时创建的是哪个子类的对象,就调用该子类中重写的那个方法
- 在执行期间(而非编译期间)判断所引用对象的实际类型,根据其实际类型调用相应的方法
- 多态的优点
- 简化代码
- 改善代码的组织性和可读性
- 易于扩展
练习
1、设计2个类,要求如下:
2.1 定义一个汽车类Vehicle,
2.1.1 属性包括:汽车品牌brand(String类型)、颜色color(String类型)和速度speed(int类型)。
2.1.2 提供两个构造方法。
2.1.3 为属性提供set/get方法。
2.1.4 定义一个一般方法show(),打印Vehicle属性例如黑色的奔驰速度是240
2.1.5 在main方法中创建一个品牌为“奔驰”,颜色为“黑色”,速度为240的Vehicle对象,调用show方法。
2.2 定义一个Vehicle类的子类轿车类Car,要求如下:
2.2.1 轿车有自己的属性载人数loader(int 类型)。
2.2.2 提供该类初始化属性的构造方法。
2.2.3 重写show(),打印Car属性例如红色的本田速度是240载人数是5
2.2.4 在main方法中创建一个品牌为“本田”,颜色为“红色”,速度为240,载人数为5 Car对象,调用show方法。
package com.tech.javase.ch7.练习1;
public class Vehicle {
// 属性
private String brand;
private String color;
private int speed;
// 构造方法
public Vehicle(String brand, String color, int speed) {
super();
this.brand = brand;
this.color = color;
this.speed = speed;
}
public Vehicle() {
super();
}
// set get
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
// 其他方法
public void show() {
System.out.println("汽车品牌是"+getBrand());
System.out.println("汽车颜色是"+getColor());
System.out.println("汽车速度是"+getSpeed());
}
}
package com.tech.javase.ch7.练习1;
public class Car extends Vehicle {
// 属性
private int loader;
// 构造方法
public Car(String brand, String color, int speed, int loader) {
super(brand, color, speed);
this.loader = loader;
}
public Car() {
super();
}
// set get
public int getLoader() {
return loader;
}
public void setLoader(int loader) {
this.loader = loader;
}
@Override
public void show() {
System.out.println("汽车品牌是"+getBrand());
System.out.println("汽车颜色是"+getColor());
System.out.println("汽车速度是"+getSpeed());
System.out.println("汽车载人数是"+getLoader());
}
}
package com.tech.javase.ch7.练习1;
public class 测试 {
public static void main(String[] args) {
// 创建对象
Vehicle v = new Vehicle("奔驰","黑色",240);
v.show();
Car c = new Car("本田","红色",240,5);
c.show();
}
}
2、设计四个类,分别如下:
3.1 设计Shape图形抽象类,颜色属性color,有两个构造方法一个showColor非抽象方法,显示图形颜色2个抽象方法,分别是:getArea计算面积、getPer计算周长、
3.2 设计 2个子类:
3.2.1 Rectangle表示矩形类,增加两个属性,Width表示长度、height表示宽度,重写getPer、getArea方法
3.2.2 Circle表示圆类,增加1个属性,radius表示半径,重写getPer、getArea方法
3.3 测试类中,在main方法中,声明创建每个子类的对象,并调用2个子类的showAll方法。
package com.tech.javase.ch7.练习2;
// 图形类
public abstract class Shape {
// 属性
private String colour; // 颜色
// 构造方法
public Shape(String colour) {
this.colour = colour;
}
public Shape() {
}
// set get
public String getColour() {
return colour;
}
public void setColour(String colour) {
this.colour = colour;
}
// 其他方法
// 打印颜色
public void printColour() {
System.out.println("颜色是"+colour);
}
// 计算面积----抽象方法
public abstract double getArea();
// 抽象类 必须定义两类方法
// 抽象的 让子类继承之后必须重写
// 非抽象的 让子类继承之后直接使用
}
package com.tech.javase.ch7.练习2;
// 矩形类 子类 继承 抽象类 图形
public class Rectangle extends Shape {
// 属性
private double length;
private double width;
// 构造方法
public Rectangle(String colour, double length, double width) {
super(colour);
this.length = length;
this.width = width;
}
public Rectangle() {
}
// set get
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
@Override
public double getArea() {
return (length+width)*2;
}
}
package com.tech.javase.ch7.练习2;
public class Cirle extends Shape{
// 属性
private double r; // 半径
// 构造方法
public Cirle(String colour, double r) {
super(colour);
this.r = r;
}
public Cirle() {
}
// get set
public double getR() {
return r;
}
public void setR(double r) {
this.r = r;
}
// 其他方法 求面积
@Override
public double getArea() {
return 3.14*r*r;
}
}
package com.tech.javase.ch7.练习2;
public class 图形测试 {
public static void main(String[] args) {
// 创建矩形类对象测试
Rectangle r = new Rectangle("黑色",3.3,4.4);
r.printColour();
r.setColour("红色");
r.printColour();
System.out.println("面积是"+r.getArea());
// 创建圆型对象
Cirle c = new Cirle("黄色",5.2);
c.printColour();
System.out.println("面积是"+c.getArea());
}
}