Java面向对象多态、抽象类、接口详解
目录
- 一、方法重写
- 1. 方法重写概述
- 2. 方法重写的注意事项
- 3. 举例
- 二、多态
- 1. 多态的概述
- 2. 多态中的成员访问特点
- 3. 多态的利弊
- 4. 向上转型与向下转型
- 5. 多态的内存图解
- 三、抽象类
- 1. 抽象类概述
- 2. 抽象类的成员特点
- 3. 抽象类练习
- 4. abstract关键字与哪些关键字冲突
- 四、接口
- 1. 接口概述
- 2. 接口的特点
- 3. 类与类、类与接口、接口与接口的关系
- 4. 抽象类与接口的区别
- 5. 接口举例
一、方法重写
1. 方法重写概述
- 什么是方法重写
方法重写是在继承中出现,当子类对父类所提供的方法不满意是可以对方法重写,又称为方法覆盖、方法复写。重写的方法与父类中的原方法的方法声明(方法名、参数列表、返回值)一样 - 应用
当子类需要父类的功能,而父类提供的功能又无法完全满足子类的需求的时候,可以重写父类的方法,这样子,即沿袭了父类的功能,又满足了子类特有的需求
2. 方法重写的注意事项
- 父类私有的方法不能重写
因为父类私有的方法子类根本就无法继承,更别说重写了 - 子类重写父类方法时,访问权限不能更低,最好一致
- 父类中的静态方法,子类也必须通过静态方法进行重写
3. 举例
//定义动物类
public class Animal {public String name;public int age;public void eat() {System.out.println("吃饭");}
}
//定义猫类,继承自动物类,并对动物类所提供的eat方法进行了重写
public class Cat extends Animal {@Overridepublic void eat() {System.out.println("猫爱吃鱼");}
}
//测试类
public class MyTest {public static void main(String[] args) {Cat cat = new Cat();cat.eat();//输出“猫爱吃鱼”}
}
二、多态
1. 多态的概述
- 什么是多态
同一个事物在不同的时刻表现出来的状态 - 多态举例
cat是Cat类的一员,所以有Cat cat = new Cat();,但同时cat也是Animal类的一员,所以也有Animal animal = new Cat();Cat cat = new Cat(); Animal animal = new Cat();
- 多态的前提
- 要有继承关系
多态是建立在子类与父类之间的关系上的(必须要求) - 要有方法重写
子类有自己的独有的功能(语法不要求,但是要有) - 要有父类引用指向子类的对象
Animal animal = new Cat();
- 要有继承关系
2. 多态中的成员访问特点
-
Animal类与Cat类
public class Animal {//Animal类public String name = "animal";public int age = 100;public static void run() {System.out.println("跑步");}public Animal() {System.out.println("Animal类的无参构造");}public void eat() {System.out.println("吃饭");} } public class Cat extends Animal {//Cat类public String name = "cat";public int age = 10;public static void run() {System.out.println("猫跑步");}public Cat() {System.out.println("Cat类的无参构造");}@Overridepublic void eat() {System.out.println("猫爱吃鱼");} }
-
成员变量
- 编译看左边,运行看左边
- 举例
public class MyTest {public static void main(String[] args) {Animal animal = new Cat();//多态,用父类型去引用子类对象System.out.println(animal.name);System.out.println(animal.age);} } //执行结果: // animal // 100
-
构造方法
- 在创建子类对象的时候会优先访问父类的构造方法,对父类的数据进行初始化
- 举例
public class MyTest {public static void main(String[] args) {Animal animal = new Cat();} } // 执行结果: // Animal类的无参构造 // Cat类的无参构造
-
成员方法
- 编译在左边,运行在右边
编译的时候会先去父类中寻找成员方法,如果又,则不报错;在运行时优先执行子类中重载、写过后的方法,如果没有,则执行父类原来的方法 - 举例
public class MyTest {public static void main(String[] args) {Animal animal = new Cat();animal.eat();} } // 猫爱吃鱼 // 调用的子类的方法,也就是“右边”
- 编译在左边,运行在右边
-
静态方法
- 静态方法因为与类相关,所以算不上重写,所以还是访问父类的静态方法
- 举例
public class MyTest {public static void main(String[] args) {Animal animal = new Cat();animal.run();} } //跑步 //因为静态方法是属于类所有的,所以调用的还是父类的静态方法
3. 多态的利弊
- 优点
- 提高了代码的维护性(继承)
- 提高了代码的扩展性(多态)
- 缺点
- 不能访问子类所独有的成员方法和子类的成员变量
- 缺点的解决方案
- 创建一个子类的对象,利用对象调用
这样做可以,但是太麻烦,而且也占用空间(创建对象) - 向下转型
将父类引用强制转换为子类引用,这样就可以调用子类所独有的成员
- 创建一个子类的对象,利用对象调用
4. 向上转型与向下转型
- 向上转型
- 将子类对象的类型转换为父类的类型,即用父类的引用指向子类的对象
- 父类的引用可以调用父类的成员变量及子类重写过的方法,不能调用子类的成员变量及子类特有的方法
- 举例
public class MyTest {public static void main(String[] args) {//向上转型,将子类Cat类型的对象转为父类Animal类型Animal animalCat = new Cat();System.out.println(animalCat.name);System.out.println(animalCat.age);//可以用父类类型引用调用父类成员变量animalCat.eat();//子类重写过后的方法} }
- 向下转型
- 将向上转型为父类类型的引用再强转为原来的类型
- 这个对象最初new出来时是哪个子类的对象,最后父类的引用只能向下转型为哪个类,不能转型为父类的其他子类
- 子类的引用可以调用子类的所有的成员,包括从父类继承过来的成员
- 举例
public class MyTest {public static void main(String[] args) {//向上转型,将子类Cat类型的对象转为父类Animal类型Animal animalCat = new Cat();//向下转型,将父类类型的animalCat转换为原来的子类类型CatCat cat = (Cat) animalCat;//使用强制转换System.out.println(cat.name);System.out.println(cat.age);cat.eat();//使用子类引用调用子类的成员} }
5. 多态的内存图解
三、抽象类
1. 抽象类概述
- 为什么要有抽象类
- 在前面,我们对动物类Animal进行了实例化,也就是创建了对象,这其实是错的,对象应该是具体的某一事物,而“animal”对象一点也不具体,所以不能对Animal类进行实例化。同时,在Animal类中,有eat和sleep方法,而且给出了具体的实现,这也是不对的。
不同的动物有不同的食物种类,也有不同的睡觉时间和睡觉方式,应该由具体的子类去实现这个具体的功能,而不是由父类给出具体的实现细节,父类只需要给出定义即可,不用给出具体的实现。
- 在前面,我们对动物类Animal进行了实例化,也就是创建了对象,这其实是错的,对象应该是具体的某一事物,而“animal”对象一点也不具体,所以不能对Animal类进行实例化。同时,在Animal类中,有eat和sleep方法,而且给出了具体的实现,这也是不对的。
- 抽象方法
- 只有方法声明,而没有具体的方法体的方法,用abstract关键字修饰
- 例如
- public abstract void eat();
- 父类中如果有抽象方法,那么子类中一定要对父类中的抽象方法进行重写
- 抽象类
- 用abstract关键字修饰的类,被修饰的类不能实例化
- 例如
public abstract class Animal {public String name = "animal";public int age = 100;public abstract void eat(); }
- 抽象类中不一定有抽象方法,但是有抽象方法的类一定是抽象类
- 抽象类中构造方法的作用
- 虽然抽象类不用实例化,但是在抽象类的子类实例时,要访问父类(也就是抽象类)的数据,这个时候就需要构造方法来对父类数据初始化
- 可以用多态的形式,由具体的子类来实例抽象类
- 抽象类的子类
- 抽象类,不用重写抽象方法
- 具体的类,要重写所有父类的抽象方法
2. 抽象类的成员特点
- 成员变量
- 可以是变量,也可以是常量
- 构造方法
- 有,当子类访问父类数据时,用来对父类数据进行初始化
- 成员方法
- 抽象方法,要求子类必须重写,自己实现
- 非抽象方法,子类继承父类的实现,提高代码复用性
3. 抽象类练习
-
案例演示1
具体事物:小学生,大学生
共性:姓名,年龄,学习,睡觉 -
代码
public abstract class Student {//抽象类public static String name;public static int age;public abstract void study();//抽象方法public abstract void sleep();//抽象方法 }public class PrimarySchoolStudent extends Student {//小学生子类@Overridepublic void study() {//方法重写System.out.println("小学生上课听讲");}@Overridepublic void sleep() {//方法重写System.out.println("小学生睡得早");}public void watchAnimation() {//子类独有的方法System.out.println("小学生看动画片");} }public class UniversityStudent extends Student {//大学生子类@Overridepublic void study() {//方法重写System.out.println("大学生上台自己讲");}@Overridepublic void sleep() {//方法重写System.out.println("大学生睡得迟");}public void playCellPhone() {//子类独有的方法System.out.println("大学生玩手机");} }public class MyTest {//测试类public static void main(String[] args) {PrimarySchoolStudent smallStudent = new PrimarySchoolStudent();smallStudent.study();smallStudent.sleep();smallStudent.watchAnimation();UniversityStudent bigStudent = new UniversityStudent();bigStudent.study();bigStudent.sleep();bigStudent.playCellPhone();} }
4. abstract关键字与哪些关键字冲突
- private
- private修饰的成员是本类私有的,在类外不能访问,而抽象方法与抽象类是建立在继承的基础上的,所以冲突
- final
- final修饰的类不能被继承,修饰的方法不能被重写,修饰的成员变量是常量,所以冲突
- static
- static修饰的成员可以直接用类名调用,而抽象方法只有声明而没有方法体,使用类名调用也无意义,所以冲突
四、接口
1. 接口概述
- 为什么要有接口
- 当一个类想要拥有它原来所不具有的功能时,可以将这个功能的声明写在一个接口里面,让这个类实现这个接口就好了。
- 比如动物园中老虎可以钻火圈,老虎类中本来不具有这个功能,如果将钻火圈这个功能定义在老虎类中就显得不合适,这个时候就可以将钻火圈这个功能定义在一个接口中,让有需要的老虎实现这个接口就可以了
- 接口的含义
- 接口就是给类提供的一些额外功能,体现了扩展性
2. 接口的特点
- 用关键字interface定义
- interface 接口名{}
- 类实现接口用implements关键字
- class 类名 implements 接口名{}
- 可以多实现
- 这个类可以是抽象类,也可以是非抽象类,非抽象类要重写接口中的所有抽象方法
- 接口继承接口用extends关键字
- interface 子接口名 extends 父接口名{}
- 可以多继承
- 接口实例化
- 接口不能直接实例化
- 但可以使用多态的形式,类似于抽象类
- 接口的成员特点
- 成员变量
- 只能是静态常量
- 默认修饰符是public static final,建议显式给出
- 成员方法
- 只能是抽象方法
- 默认修饰符:public abstract,建议显式给出
- 构造方法
- 没有,接口不需要实例化,成员变量都是常量,不需要初始化,方法也不需要初始化,所以不需要构造方法
- 成员变量
3. 类与类、类与接口、接口与接口的关系
- 类与类
- 继承,只能单继承,但可以多层继承
- 类与接口
- 实现,可以多实现
- 接口与接口
- 继承,可以多继承
4. 抽象类与接口的区别
- 成员区别
- 成员变量
- 抽象类不做要求,可以是变量,也可以是常量
- 接口只能是静态常量
- 成员方法
- 抽象类不做要求,可以是抽象方法,也可以是非抽象方法
- 接口只能是抽象方法
- 构造方法
- 抽象类有,用于子类非抽象类实例时父类数据初始化
- 接口没有,不需要
- 成员变量
- 设计理念
- 抽象类中定义的是该继承体系的共性功能,是“is a”关系
- 接口中定义的是该继承体系的扩展功能,是“like a”关系
5. 接口举例
-
题目
培训机构的老师有基础班的,也有就业班的。 共性:属性:姓名,年龄功能:讲课。现在又要针对日语这种小语种单独开班, 需要部分基础班老师和部分就业班老师会说日语。 请用所学知识把上面的内容用代码体现。
-
思路
1. 先创建一个老师类 2. 由老师类继承而来基础班与就业班的老师 3. 创建讲日语接口 4. 给基础班和就业班需要会讲日语的老师实现讲日语接口 5. 测试
-
代码
public abstract class Teacher {//教师类protected String name;protected int age;public abstract void lecture();//抽象方法讲课 }public class BasicClassTeacher extends Teacher {//基础班教师类@Overridepublic void lecture() {System.out.println("基础班老师讲基础多一点");}public BasicClassTeacher() {}public BasicClassTeacher(String name, int age) {this.name = name;this.age = age;} }public class EmployClassTeacher extends Teacher {//就业班教师类@Overridepublic void lecture() {System.out.println("就业班老师讲就业方面的多一点");}public EmployClassTeacher() {}public EmployClassTeacher(String name, int age) {this.name = name;this.age = age;} }public interface SpeakJapanese {//讲日语接口public abstract void speakJapaneae();//定义抽象的讲日语方法 }public class SpeJapBCTeacher extends BasicClassTeacher implements SpeakJapanese {//会讲日语的基础班教师类@Overridepublic void speakJapaneae() {System.out.println("基础班会讲日语的老师");}public SpeJapBCTeacher() {}public SpeJapBCTeacher(String name, int age) {this.name = name;this.age = age;} }public class SpeJapECTeacher extends EmployClassTeacher implements SpeakJapanese {//会讲日语的就业班教师类@Overridepublic void speakJapaneae() {System.out.println("就业班会讲日语的老师");}public SpeJapECTeacher() {}public SpeJapECTeacher(String name, int age) {this.name = name;this.age = age;} }public class MyTest {//测试类public static void main(String[] args) {BasicClassTeacher bCTeacher = new BasicClassTeacher("张三", 20);//基础班System.out.println(bCTeacher.name);System.out.println(bCTeacher.age);bCTeacher.lecture();System.out.println("--------------分割线--------------");EmployClassTeacher eCTeacher = new EmployClassTeacher("李四", 23);//就业班System.out.println(eCTeacher.name);System.out.println(eCTeacher.age);eCTeacher.lecture();System.out.println("--------------分割线--------------");SpeJapBCTeacher sJBCTeacher = new SpeJapBCTeacher("王五", 26);//会讲日语的基础班老师System.out.println(sJBCTeacher.name);System.out.println(sJBCTeacher.age);sJBCTeacher.lecture();sJBCTeacher.speakJapaneae();System.out.println("--------------分割线--------------");SpeJapECTeacher sJECTeacher = new SpeJapECTeacher("赵六", 29);//会讲日语的就业班老师System.out.println(sJECTeacher.name);System.out.println(sJECTeacher.age);sJECTeacher.lecture();sJECTeacher.speakJapaneae();} }
新人上路,如有不足,请多多指教!
Java面向对象多态、抽象类、接口详解
目录
- 一、方法重写
- 1. 方法重写概述
- 2. 方法重写的注意事项
- 3. 举例
- 二、多态
- 1. 多态的概述
- 2. 多态中的成员访问特点
- 3. 多态的利弊
- 4. 向上转型与向下转型
- 5. 多态的内存图解
- 三、抽象类
- 1. 抽象类概述
- 2. 抽象类的成员特点
- 3. 抽象类练习
- 4. abstract关键字与哪些关键字冲突
- 四、接口
- 1. 接口概述
- 2. 接口的特点
- 3. 类与类、类与接口、接口与接口的关系
- 4. 抽象类与接口的区别
- 5. 接口举例
一、方法重写
1. 方法重写概述
- 什么是方法重写
方法重写是在继承中出现,当子类对父类所提供的方法不满意是可以对方法重写,又称为方法覆盖、方法复写。重写的方法与父类中的原方法的方法声明(方法名、参数列表、返回值)一样 - 应用
当子类需要父类的功能,而父类提供的功能又无法完全满足子类的需求的时候,可以重写父类的方法,这样子,即沿袭了父类的功能,又满足了子类特有的需求
2. 方法重写的注意事项
- 父类私有的方法不能重写
因为父类私有的方法子类根本就无法继承,更别说重写了 - 子类重写父类方法时,访问权限不能更低,最好一致
- 父类中的静态方法,子类也必须通过静态方法进行重写
3. 举例
//定义动物类
public class Animal {public String name;public int age;public void eat() {System.out.println("吃饭");}
}
//定义猫类,继承自动物类,并对动物类所提供的eat方法进行了重写
public class Cat extends Animal {@Overridepublic void eat() {System.out.println("猫爱吃鱼");}
}
//测试类
public class MyTest {public static void main(String[] args) {Cat cat = new Cat();cat.eat();//输出“猫爱吃鱼”}
}
二、多态
1. 多态的概述
- 什么是多态
同一个事物在不同的时刻表现出来的状态 - 多态举例
cat是Cat类的一员,所以有Cat cat = new Cat();,但同时cat也是Animal类的一员,所以也有Animal animal = new Cat();Cat cat = new Cat(); Animal animal = new Cat();
- 多态的前提
- 要有继承关系
多态是建立在子类与父类之间的关系上的(必须要求) - 要有方法重写
子类有自己的独有的功能(语法不要求,但是要有) - 要有父类引用指向子类的对象
Animal animal = new Cat();
- 要有继承关系
2. 多态中的成员访问特点
-
Animal类与Cat类
public class Animal {//Animal类public String name = "animal";public int age = 100;public static void run() {System.out.println("跑步");}public Animal() {System.out.println("Animal类的无参构造");}public void eat() {System.out.println("吃饭");} } public class Cat extends Animal {//Cat类public String name = "cat";public int age = 10;public static void run() {System.out.println("猫跑步");}public Cat() {System.out.println("Cat类的无参构造");}@Overridepublic void eat() {System.out.println("猫爱吃鱼");} }
-
成员变量
- 编译看左边,运行看左边
- 举例
public class MyTest {public static void main(String[] args) {Animal animal = new Cat();//多态,用父类型去引用子类对象System.out.println(animal.name);System.out.println(animal.age);} } //执行结果: // animal // 100
-
构造方法
- 在创建子类对象的时候会优先访问父类的构造方法,对父类的数据进行初始化
- 举例
public class MyTest {public static void main(String[] args) {Animal animal = new Cat();} } // 执行结果: // Animal类的无参构造 // Cat类的无参构造
-
成员方法
- 编译在左边,运行在右边
编译的时候会先去父类中寻找成员方法,如果又,则不报错;在运行时优先执行子类中重载、写过后的方法,如果没有,则执行父类原来的方法 - 举例
public class MyTest {public static void main(String[] args) {Animal animal = new Cat();animal.eat();} } // 猫爱吃鱼 // 调用的子类的方法,也就是“右边”
- 编译在左边,运行在右边
-
静态方法
- 静态方法因为与类相关,所以算不上重写,所以还是访问父类的静态方法
- 举例
public class MyTest {public static void main(String[] args) {Animal animal = new Cat();animal.run();} } //跑步 //因为静态方法是属于类所有的,所以调用的还是父类的静态方法
3. 多态的利弊
- 优点
- 提高了代码的维护性(继承)
- 提高了代码的扩展性(多态)
- 缺点
- 不能访问子类所独有的成员方法和子类的成员变量
- 缺点的解决方案
- 创建一个子类的对象,利用对象调用
这样做可以,但是太麻烦,而且也占用空间(创建对象) - 向下转型
将父类引用强制转换为子类引用,这样就可以调用子类所独有的成员
- 创建一个子类的对象,利用对象调用
4. 向上转型与向下转型
- 向上转型
- 将子类对象的类型转换为父类的类型,即用父类的引用指向子类的对象
- 父类的引用可以调用父类的成员变量及子类重写过的方法,不能调用子类的成员变量及子类特有的方法
- 举例
public class MyTest {public static void main(String[] args) {//向上转型,将子类Cat类型的对象转为父类Animal类型Animal animalCat = new Cat();System.out.println(animalCat.name);System.out.println(animalCat.age);//可以用父类类型引用调用父类成员变量animalCat.eat();//子类重写过后的方法} }
- 向下转型
- 将向上转型为父类类型的引用再强转为原来的类型
- 这个对象最初new出来时是哪个子类的对象,最后父类的引用只能向下转型为哪个类,不能转型为父类的其他子类
- 子类的引用可以调用子类的所有的成员,包括从父类继承过来的成员
- 举例
public class MyTest {public static void main(String[] args) {//向上转型,将子类Cat类型的对象转为父类Animal类型Animal animalCat = new Cat();//向下转型,将父类类型的animalCat转换为原来的子类类型CatCat cat = (Cat) animalCat;//使用强制转换System.out.println(cat.name);System.out.println(cat.age);cat.eat();//使用子类引用调用子类的成员} }
5. 多态的内存图解
三、抽象类
1. 抽象类概述
- 为什么要有抽象类
- 在前面,我们对动物类Animal进行了实例化,也就是创建了对象,这其实是错的,对象应该是具体的某一事物,而“animal”对象一点也不具体,所以不能对Animal类进行实例化。同时,在Animal类中,有eat和sleep方法,而且给出了具体的实现,这也是不对的。
不同的动物有不同的食物种类,也有不同的睡觉时间和睡觉方式,应该由具体的子类去实现这个具体的功能,而不是由父类给出具体的实现细节,父类只需要给出定义即可,不用给出具体的实现。
- 在前面,我们对动物类Animal进行了实例化,也就是创建了对象,这其实是错的,对象应该是具体的某一事物,而“animal”对象一点也不具体,所以不能对Animal类进行实例化。同时,在Animal类中,有eat和sleep方法,而且给出了具体的实现,这也是不对的。
- 抽象方法
- 只有方法声明,而没有具体的方法体的方法,用abstract关键字修饰
- 例如
- public abstract void eat();
- 父类中如果有抽象方法,那么子类中一定要对父类中的抽象方法进行重写
- 抽象类
- 用abstract关键字修饰的类,被修饰的类不能实例化
- 例如
public abstract class Animal {public String name = "animal";public int age = 100;public abstract void eat(); }
- 抽象类中不一定有抽象方法,但是有抽象方法的类一定是抽象类
- 抽象类中构造方法的作用
- 虽然抽象类不用实例化,但是在抽象类的子类实例时,要访问父类(也就是抽象类)的数据,这个时候就需要构造方法来对父类数据初始化
- 可以用多态的形式,由具体的子类来实例抽象类
- 抽象类的子类
- 抽象类,不用重写抽象方法
- 具体的类,要重写所有父类的抽象方法
2. 抽象类的成员特点
- 成员变量
- 可以是变量,也可以是常量
- 构造方法
- 有,当子类访问父类数据时,用来对父类数据进行初始化
- 成员方法
- 抽象方法,要求子类必须重写,自己实现
- 非抽象方法,子类继承父类的实现,提高代码复用性
3. 抽象类练习
-
案例演示1
具体事物:小学生,大学生
共性:姓名,年龄,学习,睡觉 -
代码
public abstract class Student {//抽象类public static String name;public static int age;public abstract void study();//抽象方法public abstract void sleep();//抽象方法 }public class PrimarySchoolStudent extends Student {//小学生子类@Overridepublic void study() {//方法重写System.out.println("小学生上课听讲");}@Overridepublic void sleep() {//方法重写System.out.println("小学生睡得早");}public void watchAnimation() {//子类独有的方法System.out.println("小学生看动画片");} }public class UniversityStudent extends Student {//大学生子类@Overridepublic void study() {//方法重写System.out.println("大学生上台自己讲");}@Overridepublic void sleep() {//方法重写System.out.println("大学生睡得迟");}public void playCellPhone() {//子类独有的方法System.out.println("大学生玩手机");} }public class MyTest {//测试类public static void main(String[] args) {PrimarySchoolStudent smallStudent = new PrimarySchoolStudent();smallStudent.study();smallStudent.sleep();smallStudent.watchAnimation();UniversityStudent bigStudent = new UniversityStudent();bigStudent.study();bigStudent.sleep();bigStudent.playCellPhone();} }
4. abstract关键字与哪些关键字冲突
- private
- private修饰的成员是本类私有的,在类外不能访问,而抽象方法与抽象类是建立在继承的基础上的,所以冲突
- final
- final修饰的类不能被继承,修饰的方法不能被重写,修饰的成员变量是常量,所以冲突
- static
- static修饰的成员可以直接用类名调用,而抽象方法只有声明而没有方法体,使用类名调用也无意义,所以冲突
四、接口
1. 接口概述
- 为什么要有接口
- 当一个类想要拥有它原来所不具有的功能时,可以将这个功能的声明写在一个接口里面,让这个类实现这个接口就好了。
- 比如动物园中老虎可以钻火圈,老虎类中本来不具有这个功能,如果将钻火圈这个功能定义在老虎类中就显得不合适,这个时候就可以将钻火圈这个功能定义在一个接口中,让有需要的老虎实现这个接口就可以了
- 接口的含义
- 接口就是给类提供的一些额外功能,体现了扩展性
2. 接口的特点
- 用关键字interface定义
- interface 接口名{}
- 类实现接口用implements关键字
- class 类名 implements 接口名{}
- 可以多实现
- 这个类可以是抽象类,也可以是非抽象类,非抽象类要重写接口中的所有抽象方法
- 接口继承接口用extends关键字
- interface 子接口名 extends 父接口名{}
- 可以多继承
- 接口实例化
- 接口不能直接实例化
- 但可以使用多态的形式,类似于抽象类
- 接口的成员特点
- 成员变量
- 只能是静态常量
- 默认修饰符是public static final,建议显式给出
- 成员方法
- 只能是抽象方法
- 默认修饰符:public abstract,建议显式给出
- 构造方法
- 没有,接口不需要实例化,成员变量都是常量,不需要初始化,方法也不需要初始化,所以不需要构造方法
- 成员变量
3. 类与类、类与接口、接口与接口的关系
- 类与类
- 继承,只能单继承,但可以多层继承
- 类与接口
- 实现,可以多实现
- 接口与接口
- 继承,可以多继承
4. 抽象类与接口的区别
- 成员区别
- 成员变量
- 抽象类不做要求,可以是变量,也可以是常量
- 接口只能是静态常量
- 成员方法
- 抽象类不做要求,可以是抽象方法,也可以是非抽象方法
- 接口只能是抽象方法
- 构造方法
- 抽象类有,用于子类非抽象类实例时父类数据初始化
- 接口没有,不需要
- 成员变量
- 设计理念
- 抽象类中定义的是该继承体系的共性功能,是“is a”关系
- 接口中定义的是该继承体系的扩展功能,是“like a”关系
5. 接口举例
-
题目
培训机构的老师有基础班的,也有就业班的。 共性:属性:姓名,年龄功能:讲课。现在又要针对日语这种小语种单独开班, 需要部分基础班老师和部分就业班老师会说日语。 请用所学知识把上面的内容用代码体现。
-
思路
1. 先创建一个老师类 2. 由老师类继承而来基础班与就业班的老师 3. 创建讲日语接口 4. 给基础班和就业班需要会讲日语的老师实现讲日语接口 5. 测试
-
代码
public abstract class Teacher {//教师类protected String name;protected int age;public abstract void lecture();//抽象方法讲课 }public class BasicClassTeacher extends Teacher {//基础班教师类@Overridepublic void lecture() {System.out.println("基础班老师讲基础多一点");}public BasicClassTeacher() {}public BasicClassTeacher(String name, int age) {this.name = name;this.age = age;} }public class EmployClassTeacher extends Teacher {//就业班教师类@Overridepublic void lecture() {System.out.println("就业班老师讲就业方面的多一点");}public EmployClassTeacher() {}public EmployClassTeacher(String name, int age) {this.name = name;this.age = age;} }public interface SpeakJapanese {//讲日语接口public abstract void speakJapaneae();//定义抽象的讲日语方法 }public class SpeJapBCTeacher extends BasicClassTeacher implements SpeakJapanese {//会讲日语的基础班教师类@Overridepublic void speakJapaneae() {System.out.println("基础班会讲日语的老师");}public SpeJapBCTeacher() {}public SpeJapBCTeacher(String name, int age) {this.name = name;this.age = age;} }public class SpeJapECTeacher extends EmployClassTeacher implements SpeakJapanese {//会讲日语的就业班教师类@Overridepublic void speakJapaneae() {System.out.println("就业班会讲日语的老师");}public SpeJapECTeacher() {}public SpeJapECTeacher(String name, int age) {this.name = name;this.age = age;} }public class MyTest {//测试类public static void main(String[] args) {BasicClassTeacher bCTeacher = new BasicClassTeacher("张三", 20);//基础班System.out.println(bCTeacher.name);System.out.println(bCTeacher.age);bCTeacher.lecture();System.out.println("--------------分割线--------------");EmployClassTeacher eCTeacher = new EmployClassTeacher("李四", 23);//就业班System.out.println(eCTeacher.name);System.out.println(eCTeacher.age);eCTeacher.lecture();System.out.println("--------------分割线--------------");SpeJapBCTeacher sJBCTeacher = new SpeJapBCTeacher("王五", 26);//会讲日语的基础班老师System.out.println(sJBCTeacher.name);System.out.println(sJBCTeacher.age);sJBCTeacher.lecture();sJBCTeacher.speakJapaneae();System.out.println("--------------分割线--------------");SpeJapECTeacher sJECTeacher = new SpeJapECTeacher("赵六", 29);//会讲日语的就业班老师System.out.println(sJECTeacher.name);System.out.println(sJECTeacher.age);sJECTeacher.lecture();sJECTeacher.speakJapaneae();} }
新人上路,如有不足,请多多指教!
发布评论