【JavaSE】抽象类与接口

1.抽象类的定义与使用

定义:抽象类只是在普通类的基础上扩充了一些抽象方法而已。

抽象方法:指的是只声明而未实现的方法(没有方法体)

所有抽象方法要求使用abstract来定义,并且抽象方法所在的类也一定要使用abstract来定义,表示抽象类。

例:定义一个抽象类

abstract class Person{
    //属性
    private String name;
    //普通方法
    public String getName(){
        return this.name;
    }
    public void setName(String name){
        this.name = name;
    }
    //抽象方法,所有抽象方法上不包含方法体
    public abstract void getPersonInfo();
}

通过以上代码发现,其实抽象类就是比普通类多了一些抽象方法而已。

2.抽象类的使用原则

a.所有的抽象类必须有子类,因此abstract与final不能共同使用(用abstract修饰的类必须有子类,用final修饰的不能被继承,即不能有子类)

 

b.抽象类的子类必须覆写抽象类的所有抽象方法(前提是子类不是一个抽象类,是一个普通类),因此abstract不能与private同时使用(被private封装后,子类看不到方法,所以不会被覆写)

 

c.抽象类要想创建实例化对象,必须通过子类向上转型为其实例化(抽象类无法创建实例化对象)

abstract class Person{
    //属性
    private String name;
    //普通方法
    public String getName(){
        return this.name;
    }
    public void setName(String name){
        this.name = name;
    }
    //抽象方法,所有抽象方法上不包含方法体
    public abstract void getPersonInfo();
}

class Student extends Person{
    @Override
    public void getPersonInfo() {
        System.out.println("子类继承抽象类");
    }
}
public class Test2{
    public static void main(String[] args){
        Person per = new Student();
        per.getPersonInfo();
    }
}

3.抽象类的相关规定

3.1抽象类也允许提供构造方法,并且子类也照样遵循对象实例化流程,先调用父类构造方法而后调用子类构造方法

abstract class Person{
    //属性
    private String name;
    public Person(){
        System.out.println("******");
    }
    //普通方法
    public String getName(){
        return this.name;
    }
    public void setName(String name){
        this.name = name;
    }
    //抽象方法,所有抽象方法上不包含方法体
    public abstract void getPersonInfo();
}

class Student extends Person{
    public Student(){
        System.out.println("######");
    }
    @Override
    public void getPersonInfo() {
        System.out.println("子类继承抽象类");
    }
}
public class Test2{
    public static void main(String[] args){
        new Student();
    }
}

3.2抽象类中允许不定义任何抽象方法,但是此时抽象类依然无法创建实例化对象

abstract class Person{
    public Person(){
        System.out.println("******");
    }
}

class Student extends Person{
    public Student(){
        System.out.println("######");
    }
}
public class Test2{
    public static void main(String[] args){
        new Person();
    }
}

3.3abstract与final不能一起使用,abstract与private也不能一起使用

3.4内部抽象类(子类继承抽象类,只需要关心父类的直接抽象方法,不管内部类的抽象方法)

abstract class Person{
    public abstract void fun();
    abstract class B{
        public abstract void fun1();
    }
}

class Student extends Person{
    @Override
    public void fun() {}
    class C extends B{
        @Override
        public void fun1() {}
    }
}
public class Test2{
    public static void main(String[] args){
        new Student();
    }
}

注意:只有方法声明,没有方法体不一定就是抽象方法,还有可能是本地方法

4.模板设计模式-基于抽象类的设计模式,核心是封装算法

        模板方法定义了一个算法的步骤,并允许子类为一个或多个步骤提供具体实现。

        模板模式的具体定义:在一个方法中定义一个算法的骨架,并将一些具体步骤延迟到子类中实现。模板模式使得子类可以在不改变算法结构的基础上,重新具体定义算法中的某些步骤。

例:咖啡与茶的冲泡方法

初级版本:

class Coffee{
    //咖啡冲泡法
    void prepareRecipe(){
        boilWater();
        brewCoffeeGrings();
        pourInCup();
        addSugarAndMilk();
    }
    //将水煮沸
    public void boilWater(){
        System.out.println("将水煮沸");
    }
    //冲泡咖啡
    public void brewCoffeeGrings(){
        System.out.println("冲泡咖啡");
    }
    //把咖啡倒进杯子中
    public void pourInCup(){
        System.out.println("把咖啡倒进杯子中");
    }
    //加糖和牛奶
    public void addSugarAndMilk(){
        System.out.println("加糖和牛奶");
    }
}
class Tea{
    void prepareRecipe(){
        boilWater();
        steepTeaBag();
        pourInCup();
        addLemon();
    }
    //将水煮沸
    public void boilWater(){
        System.out.println("将水煮沸");
    }
    //冲泡茶
    public void steepTeaBag(){
        System.out.println("冲泡茶");
    }
    //把茶倒进被子里
    public void pourInCup(){
        System.out.println("把茶倒进杯子中");
    }
    //加柠檬
    public void addLemon(){
        System.out.println("加柠檬");
    }
}
public class test{
    public static void main(String[] args){
        Coffee coffee = new Coffee();
        Tea tea = new Tea();
        coffee.prepareRecipe();
        tea.prepareRecipe();
    }
}

        但是通过以上的方法,可以发现在这两个类中发现了重复代码。既然茶和咖啡是如此的相似,就可以将共同的部分提取出来,放在一个基类中。

 

 由于prepareRecipe()在每个类中都不一样,所以定义为抽象方法,boilWater()和pourInCup()方法被两个子类所共享,因此定义在超类中。每个子类都覆盖了prepareRecipe()方法并实现了自己的冲泡法。

重新设计后,使用模板模式方法如下:

//咖啡因饮料是一个抽象类
abstract class CaffeineBeverge{
//模板方法
    //现在用一个prepareRecipe()方法处理茶和咖啡
    //声明为final的原因是想让子类只能用这个方法,而不能覆盖这个方法
    final void prepareRecipe(){
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }
    //咖啡喝茶处理这些方法不同,因此这两个方法必须被声明为抽象方法,留给子类实现
    abstract void brew();
    abstract void addCondiments();
    public void boilWater(){
        System.out.println("将水煮沸");
    }
    public void pourInCup(){
        System.out.println("将饮料到进杯子中");
    }
}

class Coffee extends CaffeineBeverge{
    public void brew(){
        System.out.println("冲泡咖啡");
    }
    public void addCondiments(){
        System.out.println("加糖和牛奶");
    }
}
class Tea extends CaffeineBeverge{
    public void brew(){
        System.out.println("冲泡茶");
    }
    public void addCondiments(){
        System.out.println("加柠檬");
    }
}
public class test{
    public static void main(String[] args){
        CaffeineBeverge coffee = new Coffee();
        CaffeineBeverge tea = new Tea();
        coffee.prepareRecipe();
        tea.prepareRecipe();
    }
}

此时的类图为:

模板方法带来的好处:

不好的茶或咖啡的实现模板方法提供的咖啡因饮料
Coffee或Tea主导的一切,控制算法由超类主导一切,它拥有算法,并且保护这个算法
Coffee与Tea之间存在重复代码有超类的存在,因此可以将代码复用最大化
对于算法所做的代码改变,需要打开各个子类修改很多地方算法只存在一个地方,容易修改
弹性差,新种类的饮料加入需要做很多工作弹性高,新饮料的加入只需要实现自己的冲泡和加料方法即可
算法的知识和它的实现分散在许多类中超类专注于算法本身,而由子类提供完整的实现

重点:在所有的设计模式中,共同的特点就是第三方解耦(提出公共部分)。

5.接口的定义与使用

接口优先原则:在一个操作既可以使用抽象类又可以使用接口的时候,优先考虑使用接口。

接口的定义:接口就是抽象方法与全局常量的集合(JDK8之前)。

接口使用interface关键字定义。

interface IMessage{
    public static final String MSG = "10";  //全局常量
    public abstract void print();  //抽象方法
}

子类实现接口使用implements关键字,并且可以同时实现多个父接口(可以使用接口来实现多继承)。

        由于接口里面存在有抽象方法,所以接口对象不可能直接使用关键字new进行实例化的操作,但是可以通过子类对象向上转型进行实例化的操作。

interface IMessage{
    public static final String MSG = "10";  //全局
    public abstract void print();  //抽象方法
}
interface INews{
    public abstract String getNews();
}
class MessageImpl implements IMessage,INews{
    public void print(){
        System.out.println(IMessage.MSG);
    }
    public String getNews(){
        return IMessage.MSG;    //访问常量都建议加上类名称
    }
}
public class test{
    public static void main(String[] args){
        IMessage m = new MessageImpl();  //子类向上转型,为父接口实例化对象
        m.print();  //调用被子类覆写过的方法
        //父接口间的相互转换
I       News n = (INews) m;
        System.out.println(n.getNews());
    }
}

        向上转型为的是参数统一化,标准化。抽象类和接口中所有的抽象方法在子类中都被覆写,实现了多态的特性。

5.1接口的使用限制

5.1.1接口中只有public权限(不管是属性还是方法,其权限均为public,如果不写public也是public权限)

interface IMessage{
    public static final String MSG = "10";  //全局
    abstract void print();  //抽象方法
}
class MessageImpl implements IMessage{
    void print(){    //默认为default权限
        System.out.println(IMessage.MSG);
    }
}

由于接口之中只是全局常量和抽象方法的集合,所以以下两种的定义格式效果都是一样的。

完整格式简化格式

interface IMessage{

    public static final String MSG = “10”;

    public abstract void print()

}

interface IMessage{

    String MSG = “10”;

    void print();

}

接口中public static final,abstract均可以省略

阿里编码规约:接口中方法和属性不要任何修饰符,public也不要加,保证代码简洁性。

5.1.2当一个子类既需要实现接口又需要继承抽象类时,请先使用extends继承一个抽象类,而后使用implements实现多个接口。

父类和父接口之间也可以互相转化

interface IMessage{
    void print();  //抽象方法
}
abstract class News{
    //抽象类中方法前面的abstract不能省略,否则就是普通方法
    public abstract void getNews();
}
class MessageImpl extends News implements IMessage{
    public void print(){    //默认为default权限
        System.out.println("I am a Student");
    }
    public void getNews(){
        System.out.println("I am News");
    }
}
public class test{
    public static void main(String[] args){
        IMessage m = new MessageImpl();  //子类向上转型,为父接口实例化对象
        m.print();  //MessageImpl是抽象类和接口的共同子类
        News news = (News) m;
        news.getNews();
    }
}

5.1.3抽象类可以使用implements实现接口,但是接口不能entends抽象类(抽象类中可以有普通方法,构造方法,抽象方法,但是接口中只有抽象方法和全局常量。)

抽象类可以不实现接口中的抽象方法。

interface IMessage{
    void print();  //抽象方法
}
abstract class News implements IMessage{  //News为抽象类,可以不实现Imessage中的抽象方法
    public abstract void getNews();   //抽象类中方法前面的abstract不能省略,否则就是普通方法
}
class MessageImpl extends News implements IMessage{
    public void print(){    
        System.out.println("I am a Student");
    }
    public void getNews(){
        System.out.println("I am News");
    }
}
public class test{
    public static void main(String[] args){
        IMessage m = new MessageImpl();  //子类向上转型,为父接口实例化对象
        m.print();  //MessageImpl是抽象类和接口的共同子类
        News news = (News) m;
        news.getNews();
    }
}

5.1.4接口可以使用extends继承多个父接口(接口多继承)

interface A{
    void printA();
}
interface B{
    void printB();
}
interface C extends A,B{  //接口多继承
    void printC();
}
public class test{
    public static void main(String[] args){
        
    }
}

5.2接口的应用

5.2.1定义操作标准

5.2.2表示一种能力或者进行一项操作

5.2.3在分布式开发中暴露远程服务方法

例:实现电脑上可以使用任何usb设备(U盘,打印机等等)

定义一个usb标准

interface USB{
    public void plugIn(); //将USB设备插入电脑
    public void setup(); //安装USB驱动
    public void work(); //进行工作
}

 

定义电脑类

class Computer{
    public void plugin(USB usb){
        usb.plugIn();
        usb.setup();
        usb.work();
    }
}

 

定义USB子类

class UDisk implements USB{
    @Override
    public void plugIn() {
        System.out.println("U盘插入电脑");
    }

    @Override
    public void setup() {
        System.out.println("安装U盘驱动");
    }

    @Override
    public void work() {
        System.out.println("U盘正常使用");
    }
}

class PrintDisk implements USB{
    @Override
    public void plugIn() {
        System.out.println("打印机插入电脑");
    }

    @Override
    public void setup() {
        System.out.println("安装打印机驱动");
    }

    @Override
    public void work() {
        System.out.println("打印机正常使用");
    }
}

 

 测试类

public class Test2{
    public static void main(String[] args){
        Computer computer = new Computer();
        computer.plugin(new UDisk());
        computer.plugin(new PrintDisk());
    }
}

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gx1500291

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值