• 抽象类和接口的定义以及区别


    抽象类

    定义

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

    解释

    比如一个food类,我们知道他是一个食物,但是不知道它的形状、大小、味道等等,所以它是抽象的,需要一个具体的饼干,面条来给它特定的描述。

    特点

    • 1) 不能被实例化

    这个我考虑很久,查阅了一些资料,个人理解有几点:

    1. 空间分配,内存垃圾问题。在实例化对象的时候(new food())会开辟一个堆内存空间,而它没有实现的方法,是个东西,但没用。那就是垃圾。
    2. 安全。如果调用未实现的类就会报异常。比如
    public abstract class Food{
                  
                public void print(){
                    System.out.println("un_abstract method");
                }
                 
                public abstract void abstractmethod();
          }
    

    假设我们new一个对象出来,Food food = new Food(),那么执行food.abstractmethod呢?
    3. 面向对象思想不允许。可能也是最重要的吧。面向对象领域的一切都是对象,抽象在问题领域是没有概念的。在映射到现实社会的模拟,抽象是没有意义的。简单的来说,你实例化一个抽象的东西能干吗,没有实际的意义,违背了面向对象思想。

    关于这三点,属于个人观点,希望得到探讨和批评,不保证正确性

    • 2) 抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
    public abstract class Person{
        private String name;  // 变量
        private String address;
        public Employee(String name, String address){  // 构造方法
            this.name = name;
            this.address = address;
        }
        
        public abstract void cry();  //  抽象方法
        
        public void jump(){  // 普通方法
            System.out.println(this.name + "跳起来了")
        }
        
        // getter/setter 略
    }
    
    • 3)类中有抽象方法就必须定义为抽象类,抽象类中不一定包含抽象方法;

    关于抽象类中不一定包含抽象方法,这个也有点钻牛角尖问题。如果一个抽象类不包含任何抽象方法,为何还要设计为抽象类?所以暂且记住这个概念吧,不必去深究为什么。

    • 4)抽象类必须被继承使用。子类必须重写父类所有抽象方法或者声明自己为抽象类(实现部分抽象方法);
    public class Employee extends Person{
        private int number;
        
        public Employee(String name, String address, int number){
            super(name,address);
            this.number = number;
        }
        
        @Override
        public void cry(){  // 
            System.out.println(this.number + "在叫")
        }
        
        // public abstract void *();
        // 子类也可以继续声明自己的抽象方法,继续被继承实现
    }
    
    • 5)abstract不能与final并列修饰同一个类。
    • 6)abstract 不能与private、static、final或native并列修饰同一个方法。
    • 7)一个类只能继承一个抽象类,而一个类却可以实现多个接口。

    为什么需要抽象类?

    抽象方法和抽象类看上去是多余的,对于抽象方法,不知道如何实现,定义一个空方法体不就行了吗,而抽象类不让创建对象,看上去只是增加了一个不必要的限制。

    引入抽象方法和抽象类,是Java提供的一种语法工具,对于一些类和方法,引导使用者正确使用它们,减少被误用。

    使用抽象方法,而非空方法体,子类就知道他必须要实现该方法,而不可能忽略。

    使用抽象类,类的使用者创建对象的时候,就知道他必须要使用某个具体子类,而不可能误用不完整的父类。

    无论是写程序,还是平时做任何别的事情的时候,每个人都可能会犯错,减少错误不能只依赖人的优秀素质,还需要一些机制,使得一个普通人都容易把事情做对,而难以把事情做错。抽象类就是Java提供的这样一种机制。

    接口

    在软件工程中,接口泛指供别人调用的方法或者函数。从这里,我们可以体会到 Java 语言设计者的初衷,它是对行为的抽象。在 Java 中,定一个接口的形式如下:

    [public] interface InterfaceName {
     
    }
    

    特征

    • 1)接口中可以含有变量和方法

    但是要注意,接口中变量只能是 public static final变量,用其他报错。

    方法且只能是 public abstract 方法,用其他关键字,比如 private、protected、static、 final 等修饰会报编译错误

    • 2)接口中的方法必须都是抽象方法
    • 3)允许一个类遵循多个特定的接口
    class ClassName implements Interface1,Interface2,[....]{
    }
    

    如果一个非抽象类遵循了某个接口,就必须实现该接口中的所有方法。对于遵循某个接口的抽象类,可以不实现该接口中的抽象方法。

    抽象类和接口的区别

    1. 语法层面上

    • 抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;

    • 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;

    • 接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;

    • 一个类只能继承一个抽象类,而一个类却可以实现多个接口。

    说明抽象类只是类的另一种形式。而接口是一个公共的方法集合,不能有别的,一旦用了一个方法还得全部都得用,很纯粹,很牛XX

    2. 设计层面上

    要真正理解和区分,就要在设计层面上下功夫了,这样才能知道在什么场景下用它。

    • 抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。

    举个栗子,飞机和鸟是不同的事物,但有一个共同的特征就是会飞。因此我们可以设计的时候,设计AirplanBird两个类,但是一个动作,一种行为,不是一类事物的抽象描述。所以就可以设计一个接口Fly,包含方法fly(),然后Airplane和Bird分别根据自己的需要实现Fly这个接口。

    然后至于有不同种类的飞机,比如战斗机、民用飞机等直接继承Airplane即可,对于鸟也是类似的,不同种类的鸟直接继承Bird类即可。

    从这里可以看出,类继承属于‘是不是’的问题,你属不属于飞机类,鸟类。接口实现是‘有没有’的问题,你有没有飞这个功能。

    • 抽象是对类的抽象,是一种模板设计,而接口是对行为的抽象,是一种行为的规范。

    我认为这就话就是精髓所在。直接再举起来一个栗子:门和报警

    门都有open()close()两个动作,但现在要给门加上alarm(),这就要分析一下了。

    Dooropen()close()alarm() 属于两个不同范畴内的行为,open() 和 close() 属于门本身固有的行为特性,而 alarm() 属于延伸的附加行为。门也分很多种,玻璃门、防盗门、推拉门等等。不是所有的都具有报警功能。以后添加报警装置,也只是增加了一个报警功能。

    因此最好的解决办法是单独将报警设计为一个接口,包含 alarm() 行为,Door 设计为单独的一个抽象类,包含 openclose 两种行为。再设计一个报警门继承 Door 类和实现 Alarm 接口。

    即:

    public abstract class Door{
       public abstract void open();
       public abstract void close();
    }
    
    interface Alarm{
        void alarm();
    }
    
    
    class AlarmDoor extends Door implements Alarm{
         @Override
        void oepn() {
          //....
        }
         @Override
        void close() {
          //....
        }
         @Override
        void alarm() {
          //....
        }
    }
    

    参考资料:

    https://www.runoob.com/w3cnote/java-abstract-interface-different.html

    https://www.runoob.com/java/java-abstraction.html

    https://blog.csdn.net/chenssy/article/details/12858267

  • 相关阅读:
    洛谷P1057传球游戏(逆向递推递归+记忆化)
    洛谷P1433吃奶酪(正向暴力递归,回溯更新)
    洛谷P1434滑雪(逆向图的遍历搜索递归+记忆化,最长路问题)
    洛谷P1192台阶问题(逆向递推递归dfs+记忆化)
    洛谷p1025数的划分(正向暴力递归,数学排列与组合问题)
    洛谷P1141 01迷宫(图的遍历搜素递归dfs或bfs,连痛块回溯更新问题,记忆化或者并查集根结点)
    Git 版本更新--Windows
    plop-templates自动新建项目文件
    前端-随机生成测试数据-mockjs
    cookie、seseionStorage、localStorage的区别
  • 原文地址:https://www.cnblogs.com/gyyyblog/p/11805696.html
Copyright © 2020-2023  润新知