「JavaSE」抽象类&接口1

个人主页:Ice_Sugar_7
所属专栏:快来卷Java啦
欢迎点赞收藏加关注哦!

抽象类&接口1

  • 抽象类
    • 特性
    • 应用
  • 接口
    • 接口的特性
    • 使用接口

抽象类

在面向对象的概念中,所有的对象都是通过类来描绘的,
但是不是所有的类都是用来描绘对象的。如果一个类没有包含足够的信息来描绘一个具体的对象,那它就叫作抽象类

比如说,Animal是动物类,每种动物都有不同的叫声,但由于Animal并不是具体的动物,所以其内部的bark方法没办法实现
而对于Dog类和Cat类,首先猫和狗都属于动物,那么它们和Animal类就是继承关系,而且它们都是具体的动物,所以它们的bark方法可以实现
「JavaSE」抽象类&接口1_第1张图片

上一篇文章打印图形的例子中,我们发现,父类 Shape 中的 draw 方法其实啥都没做,绘制图形的工作都是由Shape的子类的draw方法来完成的

public class Shape {
    public Shape shape;
    public void draw() {
        System.out.println("画一个图形");
    }
}

像这种没有实际工作的方法,我们可以把它设计成一个抽象方法(abstract method),包含抽象方法的类我们称为抽象类

abstract class Shape {
    int a;
    int b = 10;
    private double area;
    
    //抽象方法
    abstract public void draw();
    
    //可以在抽象类中实现普通方法
    public double getArea() {  //得到绘制的图形的面积
        return this.area;
    }
}

在Java中,一个类如果被 abstract 修饰,那就称为抽象类,抽象类中被 abstract 修饰的方法称为抽象方法,抽象方法不用给出具体的实现体(即没有方法体

抽象类作为一种类,里面自然也可以添加普通方法和成员变量

特性

  • 不能实例化
    刚才我们说抽象类无法描绘一个具体的对象,所以它不能实例化对象

  • 抽象方法不能用private修饰
    要被子类重写,肯定不能设为私有

  • 抽象方法不能被final和static修饰
    因为被final或static修饰的方法不能被重写,但是抽象方法在继承时要求子类重写该方法,所以final、static和abstract是天敌

  • 抽象类必须被继承,并且继承后子类要重写父类中的抽象方法,否则子类也是抽象类,必须要使用 abstract 修饰

  • 抽象类中不一定包含抽象方法,但是有抽象方法的类一定是抽象类

  • 抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量

应用

因为抽象类不能实例化,所以要想使用的话,就要创建该抽象类的子类,然后让子类重写抽象类中的抽象方法

不过你可能会说:普通的类也可以被继承呀,普通的方法也可以被重写呀,为啥非得用抽象类和抽象方法呢?

因为使用抽象类相当于多了一重编译器的校验
比如上面画图形的例子,如果使用普通类进行继承,那不小心忘记重写子类的draw方法,那此时编译器是不会报错的
反之,如果是抽象类,编译器就会“逼你”重写

很多语法存在的意义就是为了“预防出错”
比如我们前面学过的 final 就是这样,创建的变量不希望被用户修改,所以加上 final ,这样就能够在不小心被修改的时候,让编译器及时提醒我们

充分利用编译器的校验, 在实际开发中是非常有意义的


接口

如果将抽象类再进一步抽象化,就成了接口
抽象类中可以包含成员变量,但是接口不可以(不过仍然可以包含静态变量)
抽象类中可以实现非抽象方法,但是接口只能包含方法的声明。如果要实现方法,那只能实现静态方法

下面来看怎么实现一个接口

public interface 接口名称{
	// 抽象方法
	public abstract void method1(); // public abstract 是固定搭配,可以不写
	public void method2();
	abstract void method3();
	void method4();
	// 注意:在接口中上述写法都是抽象方法,更推荐方式4,代码更简洁
}

public abstract编译器会默认给你加上的,所以不用写

关于接口的命名,需要注意:

  1. 创建接口时,接口的命名一般以大写字母 I 开头
  2. 接口的命名一般使用“形容词”词性的单词
  3. 接口中的方法和属性不要加任何修饰符号,保持代码的简洁性

接口有点类似C语言的头文件,因为头文件里面包含的就是函数声明,要具体实现这个函数的话,就得在其他源文件中实现

接口的特性

  1. 接口是一种引用类型,但是不能直接new接口的对象
  2. 接口中每一个方法都是public的抽象方法,也就是说接口中每个方法默认都是public abstract修饰的。不能改为其他,否则会报错
  3. 接口中的方法不能在接口中实现的,只能由实现接口的类来实现
  4. 重写接口中方法时,不能使用默认的访问权限(default),一定要指定用public
  5. 接口中可以有变量,它们默认会被 public static final 修饰
public interface test2 {
    int a = 2;
    final public static double b = 3.0;
}
  1. 接口中不能有静态代码块和构造方法
  2. 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class
  3. 如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类

使用接口

接口不能直接使用,必须要有一个“实现类”来实现该接口中所有抽象方法,实现接口需要用到关键字implements

接口是一种类型,它可以引用实现该接口的具体的类型

public class 类名称 implements 接口名称{
	// ...
}

举个例子:
实现笔记本电脑使用USB鼠标和键盘

  1. USB接口:包含打开设备、关闭设备功能
  2. 笔记本类:包含开机功能、关机功能、使用USB设备功能
  3. 鼠标类:实现USB接口,并具备点击功能
  4. 键盘类:实现USB接口,并具备输入功能

这里的USB接口就是一个接口它提供两种功能:连接设备、断开连接

public interface USB {
    void openDevice();
    void closeDevice();
}

笔记本类需要根据接入接口的类(鼠标、键盘类),来调用相应的类的功能

public class Computer{
    public void powerOn() {
        System.out.println("电脑开机");
    }
    
    //因为鼠标类和键盘类都实现了USB接口,所以它们都能向上转型传参给usb
    public void useService(USB usb) {
        usb.openDevice();
        if(usb instanceof Mouse) {
            Mouse mouse = (Mouse) usb;  //向下转型,使用鼠标类特有的方法
            mouse.click();
        } else if (usb instanceof Keyboard) {
            Keyboard keyboard = (Keyboard) usb;
            keyboard.input();
        }
        usb.closeDevice();
    }
    
    public void powerOff() {
        System.out.println("电脑关机");
    }
}

鼠标和键盘实现基本的功能:

//鼠标类实现USB接口
public class Mouse extends Computer implements USB{
    @Override
    public void openDevice() {
        System.out.println("连接鼠标");
    }

    public void click() {
        System.out.println("使用鼠标点击");
    }

    @Override
    public void closeDevice() {
        System.out.println("鼠标已断开连接");
    }
}

//键盘类实现USB接口
public class Keyboard extends Computer implements USB{

    @Override
    public void openDevice() {
        System.out.println("连接键盘");
    }

    public void input() {
        System.out.println("使用键盘输入");
    }

    @Override
    public void closeDevice() {
        System.out.println("键盘断开连接");
    }
}

接口解决了Java不支持多继承的问题
以动物类为例,我们想写一个Dog类来继承动物类,狗会跑,也会游泳。但不是所有动物都会这两种行为,而Java不支持多继承,但是支持一个类实现多个接口,所以我们可以把动物的行为封装成一个个接口

public class Animal {
    public String name;
    public int age;
}

//接口
public interface IFly {
    void Fly();
}

public interface ISwimming {
    void swimming();
}

public class Bird extends Animal implements IFly{
    public String color;

    @Override
    public void Fly() {
        System.out.println(this.name + "正在振动翅膀飞翔");
    }
}

//同时实现两个接口
public class Dog extends Animal implements IRun,ISwimming{
    public String color;

    @Override
    public void run() {
        System.out.println(this.name + "正在跑");
    }

    @Override
    public void swimming() {
        System.out.println(this.name + "正在游泳");
    }
}

小结:

  • 接口表达的是某个类具有某种特性。有了接口,我们在使用类的时候就不用关注具体类型,只需关注某个类是否具备某种能力
  • 方法的参数以接口类型作为形参,就可以接收所有实现这个接口的类类型(因为它们传参时会向上转型为接口类型)
    比如前面USB接口的例子,鼠标、键盘类都可以向上转型为USB类,然后实现多态

你可能感兴趣的:(快来卷Java啦,开发语言,java)