JavaSE笔记13 抽象类+接口
文章目录
Part1.抽象类:
一.抽象类和抽象方法的概述:
在继承关系中,我们将子类中的共性功能向上抽取到父类,并且对这些共性功能在父类中给出了具体的实现。但是实际上父类并不知道子类对于共性功能的具体实现,所以可以将共性功能抽象出来,具体的实现细节由子类自身的差异性,去具体实现
即:父类只需要给出共性功能的声明即可,也就是把共性功能定义为抽象的
在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类
对于抽象类和抽象方法的定义格式:
抽象类和抽象方法必须用abstract关键字修饰
抽象类格式: abstract class 类名 {}
抽象方法格式: public abstract void eat();
二.抽象类和抽象方法的特点:
抽象类与抽象方法的注意事项 |
---|
一旦类中有了抽象方法,此类必须定义为一个抽象类 |
一个抽象类中,可以没有抽象方法,当然也可以有非抽象方法 |
抽象类中可以有抽象方法,也可以有非抽象的方法。非抽象方法,可以让子类进行继承使用;抽象方法强制子类必须进行重写 |
抽象类中存在构造方法,作用是:创建子类时,先初始化父类的数据 |
抽象类不能直接创建其对象,可以直接采取多态的方式,间接进行实例化 |
作为抽象类的子类,必须重写父类中所有的抽象方法;当然也可以不重写父类中的抽象方法,将自己定义为抽象类即可 |
言外之意:抽象类的子类,要么是抽象类,要么重写抽象类中的所有抽象方法 |
代码演示抽象类和抽象方法:
public class MyTest {
public static void main(String[] args) {
/*1.一个类中有了抽象方法,此类也必须定义为抽象类
2.抽象类中可以有抽象方法,可以有非抽象方法
3.非抽象方法可以让子类继承使用,抽象方法要强制
子类必须进行重写
4.抽象类中存在构造方法,作用是:创建子类时,
先初始化父类的数据
5.抽象类不能直接创建其对象,可以采取多态的形式
进行实例化
*/
Fu fu = new Zi();
//多态形式访问成员变量,编译看父类,运行看父类
System.out.println(fu.num);//50
//多态访问成员方法,成员方法有重写,编译看父类,运行看子类
fu.show();
}
}
//父类,抽象类
abstract class Fu{
//父类的空参构造
public Fu(){
System.out.println("父类构造执行了");
}
//父类的成员变量
int num=50;
//抽象方法
public abstract void show();
}
class Zi extends Fu{
//子类的构造方法
public Zi(){
System.out.println("子类构造执行了");
}
//子类的成员变量
int num=200;
//子类重写父类中的成员方法
@Override
public void show() {
System.out.println("子类重写父类的show方法");
}
}
/*作为抽象类的子类,必须重写子类中的抽象方法,
或者将子类自己定义为一个抽象类
*/
public abstract class CC {
public abstract void cc();
public abstract void cc1();
public abstract void cc2();
}
//方式一:重写父类CC中的所有抽象的方法
class DD extends CC{
@Override
public void cc() {
}
@Override
public void cc1() {
}
@Override
public void cc2() {
}
}
//方式二:将子类ee也定义为抽象类,将父类中抽象方法继承使用
abstract class EE extends CC{
}
三.抽象类的成员特点:
抽象类的成员特点:
- 成员变量: 既可以是变量,也可以是常量
- 构造方法: 有,用于子类访问父类数据的初始化
- 成员方法: 既可以是抽象的,也可以是非抽象的
抽象类的成员方法特性:
- 抽象方法: 强制要求子类做的事情。
- 非抽象方法: 子类继承的事情,提高代码复用性
代码演示:
主测试类:
public class MyTest {
public static final int num = 100;
public static void main(String[] args) {
Person person = new Student();
person.name = "zjl";
person.age = 18;
System.out.println(person.name);
System.out.println(person.age);
person.eat();
person.sleep();
Student student = (Student) person;
student.talkLove();
System.out.println("=============================================================");
person = new Teacher();
person.name = "java沈";
person.age = 36;
System.out.println(person.name);
System.out.println(person.age);
person.eat();
person.sleep();
Teacher t = (Teacher) person;
t.teach();
// 一个类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?
//答案: 可以 . 不能创建对象.
W.hehe();
WW.hehe();
//abstract不能和哪些关键字共存?
// private abstract 矛盾,private abstract
// final abstract 矛盾
// static abstract 没有意义,静态方法,不算重写
}
}
class WW {
private WW() {
}
public static void hehe() {
}
}
abstract class W {
public static void hehe() {
}
//private abstract void haha();
// public final abstract void hehe();
// public static abstract void hh();
}
Person类:
public abstract class Person {
public String name;
public int age;
public abstract void eat();
public abstract void sleep();
}
Student类:
public class Student extends Person {
@Override
public void eat() {
System.out.println("学生爱吃麻辣烫");
}
@Override
public void sleep() {
System.out.println("学生晚上狂欢,白天睡觉");
}
public void talkLove() {
System.out.println("学生谈恋爱");
}
}
Teacher类:
public class Teacher extends Person {
@Override
public void eat() {
System.out.println("老师爱吃 燃面");
}
@Override
public void sleep() {
System.out.println("老师晚上搂着媳妇睡觉");
}
public void teach() {
System.out.println("老师教书");
}
}
运行结果:
四.抽象类与抽象方法的简答题:
1.一个类中如果没有抽象方法,可不可以定义为抽象类?如果可以,有何意义?
抽象类中可以有抽象方法,可以有非抽象方法。非抽象方法可以继承让子类进行使用,抽象方法要求子类必须进行重写。一个类中如果没有抽象方法,可以定义为抽象类。外界不能直接创建该抽象类的对象。
2.abstract关键字不能与哪些关键字进行共存?
- abstrct不能与fianl关键字进行共存:abstract强制子类重写方法,final修饰的方法不能被子类进行重写
- abstract不能与private关键字进行共存:private修饰的方法无法继承,也无法进行重写
- abstract不能与static关键字共存:静态方法不参与重写,abstract修饰的方法要求子类进行重写
Part2.接口:
一.接口的概述:
我们知道java中只支持单继承,但如果我们想定义一些功能,想让一个子类都继承实现,显然没办法做到,所有Java提供了接口这个概念。这样我们就可以用一个子类去实现多个接口。我们可以理解为接口就是特殊的抽象类
为了体现事物的扩展性,Java中就提供了接口去定义这些额外的功能,并不给出具体的是实现。将来哪些类需要需要继承这些功能,只需要实现接口就行
二.接口的特点:
接口用关键字interface表示
格式: interface 接口名 {}
类实现接口用implements表示
格式: class 类名 implements 接口名 {}
注意事项:
- 接口不能直接实例化:接口的实例化方式是按照多态的方式来实例化
- 接口的子类:
[1] 可以是抽象类。但是意义不大
[2] 可以是具体类。要重写接口中的所有抽象方法(推荐方案)
代码演示:
public class MyTest {
public static void main(String[] args) {
//接口不能直接创建对象
//子类和接口之间的关系是实现关系,implements
//可以将子类与接口之间的关系称为:父接口,子类
MyInterface myInterface=new Cat();
myInterface.jump();
}
}
/*interface定义一个接口,接口中定义的都是一些扩展的功能
哪类事物想要具备该扩展功能,需要实现该接口*/
interface MyInterface{
//接口中定义了扩展的功能:跳高
public abstract void jump();
}
//抽象类
abstract class Animal{
//抽象方法
public abstract void eat();
public abstract void sleep();
}
//类与接口的关系是实现的关系
//接口中的抽象方法,实现的类必须对方法重写
class Cat extends Animal implements MyInterface{
@Override
public void eat() {
System.out.println("小猫吃鱼");
}
@Override
public void sleep() {
System.out.println("小猫喜欢在温暖的地方睡觉");
}
@Override
public void jump() {
System.out.println("小猫经过学习学会了跳高");
}
}
三.接口中的成员特点:
- 成员变量;只能是常量,并且是静态的
默认修饰符:public static final
建议:自己手动给出 - 构造方法:接口没有构造方法
- 成员方法:只能是抽象方法
默认修饰符:public abstract
建议:自己手动给出
代码演示:
public class MyTest {
public static void main(String[] args) {
//接口中的公共静态常量,可以直接通过接口名直接调用
System.out.println(MyInterface.num);
}
}
/*接口:interface它主要定义一些扩展的功能,将来
哪些事物想要具备这些扩展功能,就可以实现这个接口
接口,其实用来定义一些规范,对于这些规范的实现,
肯定由子类来进行具体的实现
*/
interface MyInterface{
//接口中的成员变量默认为公共的静态常量
//成员变量前存在public static final的修饰符
public static final int num=30;
//接口中的方法全部都是抽象方法
//方法前存在默认public abstract修饰符
public abstract void aa();
}
四.类,接口的关系:
类,接口的关系总述 |
---|
类与类之间的关系:类与类之间形成继承关系,并且只能是单继承,可以多层继承 |
类与接口之间的关系:类与接口之间的关系是实现的关系,并且可以多实现(也就是说一个类可以实现多个接口) |
接口与接口之间的关系:接口与接口关系是继承关系,并且可以多继承 |
1.类和类之间的关系:
类与类之间的关系:类与类之间形成继承关系,并且只能是单继承,可以多层继承
代码演示:
public class MyTest1 {
public static void main(String[] args) {
//多态:父类的引用指向子类的对象
Fu fu = new Zi();
//多态访问成员变量,编译看父类,运行看父类
System.out.println(fu.num);
fu.show();
//想要访问子类中特有的成员需要向下转型
Zi zi= (Zi) fu;
System.out.println(zi.num);
}
}
//父类
class Fu{
//父类的成员变量
int num=30;
public void show(){
System.out.println("父类的show方法");
}
}
//子类
class Zi extends Fu{
//子类的成员变量
int num=100;
//子类重写父类的成员方法
@Override
public void show() {
System.out.println("子类的成员方法");
}
}
2.类和接口之间的关系:
类与接口之间的关系:类与接口之间的关系是实现的关系,并且可以多实现(也就是说一个类可以实现多个接口)
代码演示:
//接口,接口中的方法都是抽象方法,
//方法前有public abstract的默认修饰符
interface A{
public abstract void a();
public abstract void aa();
}
interface B{
public abstract void b();
}
//类与接口之间的关系:类与接口的关系是实现关系
//也就是说一个类可以实现多个接口
class C implements A,B
{
@Override
public void aa() {
}
@Override
public void a() {
}
@Override
public void b() {
}
}
3.接口和接口之间的关系:
接口与接口之间的关系:接口与接口关系是继承关系,并且可以多继承
代码演示:
interface A{
public abstract void a();
}
interface B{
public abstract void b();
}
//接口与接口之间的关系:是继承的关系,并且可以多继承
interface C extends A,B{
public abstract void c();
}
4.接口的注意事项:
- JDK1.8前,接口中全是抽象方法;JDK1.8后,对接口进行一些改变,接口中的方法可以给出具体的实现(这个方法可以是非抽象方法),要在方法前有default修饰符
- JDK1.8后,接口中可以定义静态方法
对于注意事项中的代码演示:
public class MyTest {
public static void main(String[] args) {
//JDK1.8之后,对接口有所改变
//JDK1.8之后,可以定义默认方法,给出方法的具体实现,个人认为他是为了弥补类的单继承的不足。
//JDK1.8之后,可以定义静态方法。
Y y = new Y();
y.hh();
y.gg();
GG.myGG();
}
}
class AA {
public void aa() {
}
}
class BB {
public void bb() {
}
}
interface GG {
default void gg() {
System.out.println("gg");
}
public static void myGG() {
System.out.println("ggg");
}
}
interface HH {
default void hh() {
System.out.println("hh");
}
}
class F extends AA {
}
class Y implements GG, HH {
}
interface A {
void aa();
void bb();
public default void cc() {
System.out.println("ccc");
}
}
五.抽象类与接口之间的区别:
抽象类和接口之间的区别在于以下三个方面:
- 成员区别:
类别 | 成员变量的区别 | 构造方法 | 成员方法 |
---|---|---|---|
抽象类 | 可以是变量,也可以是常量 | 有构造方法 | 可以有抽象方法,也可以有非抽象方法 |
接口 | 全部都是公共的静态常量 | 无构造方法 | 成员方法只有抽象方法(JDK1.8之后可以定义default修饰的方法,可以给出功能的具体实现,子类可以继承使用; JDK1.8之后在接口中也可以定义静态方法 |
- 关系区别:
类、接口的关系 |
---|
类与类之间的关系:继承关系,继承关系是单继承,不能多继承,可以多层继承 |
类与接口之间的关系:实现关系,可以单实现,可以多实现(一个类可以实现多个接口) |
接口与接口之间的关系:继承关系,可以单继承,可以多继承 |
- 设计理念区别:
设计理念区别 |
---|
抽象类:抽象类中定义了该继承体系中的共性功能 |
接口:接口中定义的是该继承体系中的扩展功能 |
六.关于接口的练习:
练习内容:
猫狗测试之多态+接口版
源代码:
package JiekouChouxiangDemo;
public class DogAndCatInDuoTai {
public static void main(String[] args) {
Cat lhm = new LiHuaCat();
lhm.age=2;
lhm.name="狸花猫";
System.out.println(lhm.name+"."+lhm.age);
lhm.eat();
lhm.sleep();
LiHuaCat lihuamao = (LiHuaCat) lhm;
lihuamao.cathMouse();
System.out.println("----------------------------------");
JiaFeiCat jfm = new JiaFeiCat();
lhm = jfm;
lhm.name = "加菲猫";
lhm.age = 3;
System.out.println(lhm.name+"."+lhm.age);
lhm.eat();
lhm.sleep();
Jumpinterface jumpinterface = jfm;
jumpinterface.jump();
System.out.println("----------------------------------");
Dog dog = new ErHa();
dog.name="二哈";
dog.age=4;
System.out.println(dog.name+"."+dog.age);
dog.eat();
dog.sleep();
ErHa erha = (ErHa) dog;
erha.lookDoor();
System.out.println("---------------------------------");
JiWaWa jww = new JiWaWa();
dog=jww;
dog.name="吉娃娃";
dog.age=5;
dog.eat();
dog.sleep();
Jumpinterface jumpinterface1 = jww;
jumpinterface.jump();
}
}
class Cat extends Animal{
@Override
public void eat() {
System.out.println("吃饭");
}
@Override
public void sleep() {
System.out.println("睡觉");
}
}
class Dog extends Animal{
@Override
public void eat(){
System.out.println("爱吃骨头");
}
@Override
public void sleep(){
}
}
class JiaFeiCat extends Cat implements Jumpinterface{
@Override
public void eat() {
System.out.println("加菲猫爱吃鱼罐头");
}
@Override
public void sleep() {
System.out.println("加菲猫睡席梦思");
}
@Override
public void jump() {
System.out.println("加菲猫学会了跳高");
}
}
class LiHuaCat extends Cat {
@Override
public void eat() {
System.out.println("狸花猫吃老鼠");
}
@Override
public void sleep() {
System.out.println("狸花猫睡蒲团");
}
public void cathMouse(){
System.out.println("狸花猫会抓老鼠");
}
}
class ErHa extends Dog{
@Override
public void eat() {
System.out.println("二哈爱吃排骨");
}
@Override
public void sleep() {
System.out.println("二哈睁眼睡觉");
}
public void lookDoor(){
System.out.println("二哈看门");
}
}
class JiWaWa extends Dog implements Jumpinterface{
@Override
public void eat() {
System.out.println("吉娃娃爱吃高级狗粮");
}
@Override
public void sleep() {
System.out.println("吉娃娃爱睡在狗窝");
}
@Override
public void jump() {
System.out.println("吉娃娃学会了跳高");
}
}
运行截图: