java的继承与抽象类
目录
继承类
什么是继承
继承关键字
class——定义类
interface——定义接口
extends——继承父类
implements——实现接口
extends和implements的区别
相同点
都属于Java中的继承
都发生在多各类中
不同点
extends只能单继承,implements可以实现多继承
extends继承父类时,父类中可以存在方法的默认实现
而implements在实现接口时接口中不能有方法实现
extends发生在子类和父类之间,implements发生在实现
类和接口之间
继承的概念
继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
继承: java面向对象三大特征之一
含义: 子类继承父类,可以直接使用父类的属性和方法(主要使用方法)
父类: 有时候也会被别人叫做 超类、基类。
关键字: extends
继承: 类和类之间的关系
继承的作用
子类拥有父类的属性和方法,减少重复的代码,维护性高。
代码简洁,提高了代码的复用性。
继承的特点:
1.子类可以继承父类非private属性和方法
2.子类可以有自己特有的属性和方法
3.java类的继承是单继承,但是可以多重继承 (接口的继承可以多继承)
4.子类可以重写父类的方法
Java只支持单继承,不支持多继承。
//一个类只能有一个父类,不可以有多个父类。
class C extends A{} //ok
class C extends A,B... //error
Java支持多层继承(继承体系)
class A{}
class B extends A{}
class C extends B{}
继承的规则
再父子类的继承关系中,创建子类对象,访问成员方法的规则:
创建的对象是谁,就优先用谁,如果没有就向上找
注意事项:
无论是成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类的:
继承的顺序
同一个类里面: 静态>代码块>构造方法
子父类里面: 父类静态>子类静态>父类代码块>父类构造方法>子类代码块>子类构造方法
类创建要比对象早,static是属于类的,不属于对象
在静态的里面不要调用非静态的,也不要用this和super
继承的构造方法
构造方法:
补充:
1.当一个类中没有定义构造方法的时候, 系统会默认给该类添加一个无参构造方法
2.当一个类中定义了有参构造方法的时候, 系统不会默认给无参构造方法
继承的格式
通过 extends
关键字,可以声明一个子类继承另外一个父类,定义格式如下:
class 父类 {
...
}
class 子类 extends 父类 {
...
}
继承演示,代码如下:
/*
* 定义员工类Employee,做为父类
*/
class Employee {
String name; // 定义name属性
// 定义员工的工作方法
public void work() {
System.out.println("尽心尽力地工作");
}
}
/*
* 定义讲师类Teacher 继承 员工类Employee
*/
class Teacher extends Employee {
// 定义一个打印name的方法
public void printName() {
System.out.println("name=" + name);
}
}
/*
* 定义测试类
*/
public class ExtendDemo01 {
public static void main(String[] args) {
// 创建一个讲师类对象
Teacher t = new Teacher();
// 为该员工类的name属性进行赋值
t.name = "小明";
// 调用该员工的printName()方法
t.printName(); // name = 小明
// 调用Teacher类继承来的work()方法
t.work(); // 尽心尽力地工作
}
}
在上述代码中,Teacher类通过extends关键字继承了Employee类,这样Teacher类便是Employee类的子类。从运行结果不难看出,子类虽然没有定义name属性和work()方法,但是却能访问这两个成员。这就说明,子类在继承父类的时候,会自动拥有父类的成员。
继承后的特点——成员变量
当类之间产生了关系后,其中各类中的成员变量,又产生了哪些影响呢?
成员变量不重名
如果子类父类中出现不重名的成员变量,这时的访问是没有影响的。代码如下:
class Fu {
// Fu中的成员变量。
int num = 5;
}
class Zi extends Fu {
// Zi中的成员变量
int num2 = 6;
// Zi中的成员方法
public void show() {
// 访问父类中的num,
System.out.println("Fu num="+num); // 继承而来,所以直接访问。
// 访问子类中的num2
System.out.println("Zi num2="+num2);
}
}
class ExtendDemo02 {
public static void main(String[] args) {
// 创建子类对象
Zi z = new Zi();
// 调用子类中的show方法
z.show();
}
}
演示结果:
Fu num = 5
Zi num2 = 6
成员变量重名
如果子类父类中出现重名的成员变量,这时的访问是有影响的。代码如下:
class Fu {
// Fu中的成员变量。
int num = 5;
}
class Zi extends Fu {
// Zi中的成员变量
int num = 6;
public void show() {
// 访问父类中的num
System.out.println("Fu num=" + num);
// 访问子类中的num
System.out.println("Zi num=" + num);
}
}
class ExtendsDemo03 {
public static void main(String[] args) {
// 创建子类对象
Zi z = new Zi();
// 调用子类中的show方法
z.show();
}
}
演示结果:
Fu num = 6
Zi num = 6
子父类中出现了同名的成员变量时,在子类中需要访问父类中非私有成员变量时,需要使用super
关键字,修饰父类成员变量,类似于之前学过的 this
。
使用格式:
super.父类成员变量名
子类方法需要修改,代码如下:
class Zi extends Fu {
// Zi中的成员变量
int num = 6;
public void show() {
//访问父类中的num
System.out.println("Fu num=" + super.num);
//访问子类中的num
System.out.println("Zi num=" + this.num);
}
}
演示结果:
Fu num = 5
Zi num = 6
Fu 类中的成员变量是非私有的,子类中可以直接访问。若Fu 类中的成员变量私有了,子类是不能直接访问的。通常编码时,我们遵循封装的原则,使用private修饰成员变量,那么如何访问父类的私有成员变量呢?对!可以在父类中提供公共的getXxx方法和setXxx方法。
继承后的特点——成员方法
当类之间产生了关系,其中各类中的成员方法,又产生了哪些影响呢?
成员方法不重名
如果子类父类中出现不重名的成员方法,这时的调用是没有影响的。对象调用方法时,会先在子类中查找有没有对应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。代码如下:
class Fu{
public void show(){
System.out.println("Fu类中的show方法执行");
}
}
class Zi extends Fu{
public void show2(){
System.out.println("Zi类中的show2方法执行");
}
}
public class ExtendsDemo04{
public static void main(String[] args) {
Zi z = new Zi();
//子类中没有show方法,但是可以找到父类方法去执行
z.show();
z.show2();
}
}
成员方法重名——重写(Override)
如果子类父类中出现重名的成员方法,这时的访问是一种特殊情况,叫做方法重写 (Override)。
方法重写 :子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者覆写。声明不变,重新实现。
代码如下:
class Fu {
public void show() {
System.out.println("Fu show");
}
}
class Zi extends Fu {
//子类重写了父类的show方法
public void show() {
System.out.println("Zi show");
}
}
public class ExtendsDemo05{
public static void main(String[] args) {
Zi z = new Zi();
// 子类中有show方法,只执行重写后的show方法
z.show(); // Zi show
}
}
继承后的特点——构造方法
构造方法的名字是与类名一致的。所以子类是无法继承父类构造方法的。
构造方法的作用是初始化成员变量的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个super() ,表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。代码如下:
class Fu {
private int n;
Fu(){
System.out.println("Fu()");
}
}
class Zi extends Fu {
Zi(){
// super(),调用父类构造方法
super();
System.out.println("Zi()");
}
}
public class ExtendsDemo07{
public static void main (String args[]){
Zi zi = new Zi();
}
}
输出结果:
Fu()
Zi()
抽象类
抽象类的概念
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。例如:
抽象类的作用
抽象类本身不能被实例化,要想使用只能创建该抽象类的子类,然后让那个子类重写父类中的抽象方法。
使用抽象类,实际工作不由父类完成,而应由子类完成,如果此时不小心误用父类了,使用普通类编译器不会报错,但是父类是抽象类就会在实例化的时候提示错误,让我们尽早发现问题。
特点:
抽象类可以有构造方法,但是不能创建对象,抽象类的构造方法是成员变量初始化的。
抽象类中可以有普通的成员变量,也可以有静态成员变量
抽象类里面有抽象方法,普通类里面不能有抽象方法
普通类继承了抽象类,必须重写抽象类的抽象方法
抽象类也可以有普通的方法。
抽象方法: 被abstract修饰的方法就叫抽象方法
抽象方法没有方法体;
抽象类的语法
在Java中一个类被 abstract 修饰称为抽象类,抽象类中被abstract修饰的方法被称为抽象方法,抽象方法不用给出具体的实现体。
public abstract class Animal { //抽象类,被abstract修饰
abstract void eat(); //抽象方法,被abstract修饰没有方法体
abstract void sleep();
public void run(){ //也可以增加普通方法和属性
System.out.println("跑");
}
}
注意:抽象类也是类,内部可以包含普通方法和属性和构造方法
抽象类特性
1.抽象类不能直接实例化对象
Animal animal = new Animal();
//编译报错,因为Animal是抽象的无法实例化
2.抽象方法不能被private修饰
abstract private void eat();
//编译报错,非法的修饰符组合:abstract和private
注意:抽象方法没有加访问访问修饰符,默认是public.
3.抽象方法不能被final和static修饰,因为抽象方法要被子类重写
abstract final void eat();
abstract static void sleep();
//编译报错,非法的修饰符组合
4.抽象类必须被继承,并且被继承后子类要重写父类中所有的抽象方法,否则子类也是抽象类,必须要用abstract修饰
public abstract class Animal {
abstract void eat();
abstract void sleep();
}
public class Dog extends Animal {
@Override
void eat() {
}
@Override
void sleep() {
}
}
public abstract class Cat extends Animal{
@Override
void eat() {
}
}
5. 抽象类中不一定包含抽象方法,但是有抽象方法的类一定是抽象类
6. 抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量