Java基础之抽象类和接口

  在学习了抽象类和接口之后,我对相关内容做了一些总结,主要从以下几个方面来对这块知识进行梳理。

一、什么是接口?

  接口是一组规则的集合,它规定了实现本接口的类或接口必须拥有的一组规则。体现了自然界“如果你是……则必须能……”的理念。

  概念:

    接口是一系列方法的声明,是对行为的抽象,一个接口只有方法的特征,没有方法的实现(jdk1.8以前),因此接口中的方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。

  特点:

    1、接口中的变量会被隐式地指定为public static final

    2、方法会被隐式地指定为public abstract

    3、接口中的所有方法必须是抽象方法。

    4、抽象类和接口都是对共性的提取(抽象),而接口是一种极度抽象的类型它比抽象类更“抽象”,所以一般不在接口中定义变量

  作用:

    可以为对象的行为定义一套规范

 

二、什么是抽象类?

  如果一个类中含有抽象方法,则这个类为抽象类,抽象类必须在类前用abstract关键字修饰。

  概念:

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

  特点:

    1、抽象类中含有无具体实现的方法,所以不能创建对象。

    2、抽象类除了不能实例化对象以外,其它功能跟普通类一样。

    3、由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用

  作用:

    抽象类既可以减少代码重用,又可以定义方法规范。

 

三、接口和抽象类的区别

  设计目的的区别:  

    接口是对动作的抽象,而抽象类是对根源的抽象。对于抽象类,比如男人,女人这两个类,那我们可以为这两个类设计一个更高级别的抽象类--人。对于接口,我们可以坐着吃饭,可以站着吃饭,可以用筷子吃饭,可以用叉子吃饭,那么可以把这些吃饭的动作抽象成一个接口--吃饭。所以在Java中,一个类只能继承一个抽象类(因为你不可能同时是生物又是非生物)。但是一个类可以同时实现多个接口,比如开车接口,滑冰接口,踢足球接口,游泳接口。

  语法层面的区别:   

    抽象类可以有非抽象方法,而接口中只能存在抽象方法。

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

    抽象类中可以有静态代码块和静态方法,而接口中不能含有。 一个类只能继承一个抽象类,而一个类却可以实现多个接口。

 

四、接口和抽象类的应用场景

  当你关注一个事物的本质的时候,用抽象类;当你关注一个操作的时候,用接口。

  1:类与类之间需要特定的接口进行协调,而不在乎其如何实现时,使用接口

  2:接口可以作为能够实现特定功能的标识存在,也可以是什么方法没有的纯粹标识。(Serializable,Cloneable)

  3:如果想实现多重继承的功能,那么必须使用接口

  4:规范了一组相互协调的方法,其中一些方法是共同的,与状态无关的,可以共享的,无需子类分别实现;而另一些方法却需要各个子类根据自己特定的状态来实现特定的功能

  5:定义了一组接口,但又不想强迫每个实现类都必须实现所有的接口。可以用abstract class定义一组方法体,甚至可以是空方法体,然后由子类选择自己所感兴趣的方法来覆盖。

 

五、应用Demo

  使用抽象类是为了代码的复用,而使用接口的动机是为了实现多态性。所以,如果你在为某个地方该使用接口还是抽象类而犹豫不决时,那么可以想想你的动机是什么。

抽象类Demo:
abstract class Animal{
    private String name ;        // 定义name属性
    private int age ;            // 定义age属性
    public Animal(String name,int age){
        this.name = name ;
        this.age = age ;
    }
    public String getName(){
        return this.name ;
    }
    public int getAge(){
        return this.age ;
    }
    public void say(){        // 人说话是一个具体的功能
        System.out.println(this.getContent()) ;    // 输出内容
    }
    public abstract String getContent() ;    // 说话的内容由子类决定
}
class Cat extends Animal{
    private String call;
    public Cat(String name,int age,String call){
        super(name,age) ;    // 调用父类中的构造方法
        this.call= call ;
    }
    public String getContent(){
        return    " 姓名:" + super.getName() + 
                ";年龄:" + super.getAge() + 
                ";叫声:" + this.call;
    }
}
class Dog extends Animal{
    private String call ;
    public Dog (String name,int age,String call){
        super(name,age) ;    // 调用父类中的构造方法
        this.call= call;
    }
    public String getContent(){
        return    "姓名:" + super.getName() + 
                ";年龄:" + super.getAge() + 
                ";叫声:" + this.call ;
    }
}
public class AbstractCaseDemo {

    public static void main(String args[]){
        Animal per1 = null ;    // 声明Animal 对象
        Animal per2 = null ;    // 声明Animal 对象
      per1 = new Cat("猫儿",2,"喵") ;    
        per2 = new Dog("小狗",10,"汪") ;    
        per1.say();    
        per2.say();  
    }
    
}
运行结果:
姓名:猫儿;年龄:2;叫声:喵
姓名:小狗;年龄:10;叫声:汪
--------------------- 



接口Demo:

interface USB{        // 定义了USB接口
    public void start() ;    // USB设备开始工作
    public void stop() ;    // USB设备结束工作
}
class Computer{
    public static void plugin(USB usb){    // 电脑上可以插入USB设备,向上转型,这里就相当于一个接口,只有符合这个接口的标准的类的对象(即只有继承这个接口的类的对象),才能被这个方法调用。
        usb.start() ;
        System.out.println("=========== USB 设备工作 ========") ;
        usb.stop() ;
    }
}
class Flash implements USB{
    public void start(){    // 覆写方法
        System.out.println("U盘开始工作。") ;
    }
    public void stop(){        // 覆写方法
        System.out.println("U盘停止工作。") ;
    }
}
class Print implements USB{
    public void start(){    // 覆写方法
        System.out.println("打印机开始工作。") ;
    }
    public void stop(){        // 覆写方法
        System.out.println("打印机停止工作。") ;
    }
}
public class InterfaceCaseDemo {

    public static void main(String args[]){
        Computer.plugin(new Flash()) ;
      Computer.plugin(new Print()) ;
    }
    
}

U盘开始工作。
=========== USB 设备工作 ========
U盘停止工作。
打印机开始工作。
=========== USB 设备工作 ========
打印机停止工作。

 

六、扩展内容

  为什么接口中的变量会被隐式地指定为public static final?

     三个关键字在接口中的存在原因:

    public:接口可以被其他接口继承,也可以被类实现,类与接口、接口与接口可能会形成多层级关系,采用public可以满足变量的访问范围;

    static:如果变量不是static的,那么接口必须实例化才可以访问自己的变量,接口不能被实例化,故非static的变量是无效的;

    final:如果变量不是final的,而方法是abstract的,因此接口中的方法又不可以修改变量值,虽然可以直接修改静态成员变量,但所有实现类对应的值都被修改了,此做法等同于抽象类,故需要final修饰成员变量;

  为什么Java不支持多重继承?

    第一、简单 java是一门简单,面向对象... 避免了菱形问题(C++)     有兴趣的朋友可以自己了解一下

    第二、很少用到, java设计者出于设计的一种考虑: 摒弃极少使用并且容易产生混淆的一些特性 即使它是必需的,也可以用替代设计(接口)代替。因此,Java可以在没有多重继承的情况开发者的使用也没有任何问题,这也是一个原因。

   JDK1.8之后,在接口里面可以定义静态方法和默认方法,默认方法里面是可以具备方法体的,当子类实现该接口之后,不需要重写该方法即可以调用该方法。同时带来的多继承中的一个二义性问题:如果一个类实现了两个接口(可以看做是“多继承”),这两个接口又同时都包含了一个名字相同的default方法,那么会发生什么情况? 在这样的情况下,编译器会报错。

  这里举个例子:

  

interface InterfaceWithDefaultMethod {
    void someMethod();
    default void someOtherMethod(){
        System.out.println("Default method implementation in the interface");
    }
}
interface InterfaceWithAnotherDefMethod {
    default void someOtherMethod(){
        System.out.println("Default method implementation in the interface");
    }
}
public class InterfaceTestDemo implements InterfaceWithDefaultMethod, InterfaceWithAnotherDefMethod{
    @Override
    public void someMethod() {
        System.out.println("Some method implementation in the class");
    }
    public static void main(String[] args) throws InterruptedException {
        InterfaceTestDemo def1 = new InterfaceTestDemo();
        def1.someMethod();
        def1.someOtherMethod();
    }
}


会在编译时报错
Duplicate default methods named someOtherMethod with the parameters () and () are inherited from the types InterfaceWithAnotherDefMethod and InterfaceWithDefaultMethod
提示你有重复的默认方法,需要重写

也就是说当实现的接口中有相同的默认方法时,需要自己手动去重写那个冲突的方法。

 

posted @ 2019-05-20 17:30  古镇里的鬼  阅读(108)  评论(0)    收藏  举报