接口是否可继承接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类?抽象类中是否可以有静态的main方法?

简介: 有一个面试四连击的题目:接口是否可继承接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类?抽象类中是否可以有静态的main方法?

前言


有一个面试四连击的题目:接口是否可继承接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类?抽象类中是否可以有静态的main方法?


上面这个题目我们来慢慢的剖析一下。先从基本的概念说起。


一、接口


官方解释:Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。


又到了我最喜欢打比方的环节了:我们身边最常见的接口就是电脑的usb接口了。我们可以想想,我们电脑的usb接口是不是就那么几个但是没有任何的具体的功能?但是当我们把u盘插到usb接口的时候,我们可以进行数据的传输;


当我们把鼠标插入usb接口的时候,我们可以左键打开网页、文件夹等更多的功能;当我们把键盘插入到usb接口的时候我们可以打字,等等。虽然接入不同的设备可以进行不同的操作,但是上述的设备操作都是和电脑的数据交互。


所以电脑在设置usb接口的时候,并没有实现具体的读写数据的功能,而是但不同的设备接入usb接口就可以实现不同的数据读写功能。这就是接口的好处,试想:如果每个接口都有特定的功能,鼠标要插这个接口,键盘插那个接口。那电脑就全是接口了,大大的浪费了资源,而且还不好看。


接口的特点以及重点:


  1. 并不能直接去实例化一个接口,因为接口中的方法都是抽象的,是没有方法体的。但是,我们可以使用接口类型的引用指向一个实现了该接口的对象(键盘、鼠标,…),并且可以调用这个接口中的方法。


  1. 一个类可以实现不止一个接口。键盘可以连接戴尔的接口、华硕的接口、联想的接口。


  1. 接口也可以继承,并且可以多继承。一个接口可以继承于另一个接口,或者另一些接口。比如现在的很多人电脑的usb接口不够用,所以有了usb接口拓展。


  1. 接口中所有的方法都是抽象的和public的,所有的属性都是public,static,final的。


  1. 一个类如果要实现某个接口的话,那么它必须要实现这个接口中的所有方法。我们在使用编辑器编写的时候就会自动提示:

a86121f0ed99423aba676c675eac23c9~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


否则的话会报错:

17ac2b9f5bf0433da2fdc981dd898c9c~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


先来看个接口的栗子:


public interface Demo8 {
      void say();
      int add();
    }
复制代码


声明一个类实现接口:


public class Demo7 implements Demo8 {
  public static void main(String[] args) {
    Demo7 demo7 = new Demo7();
    demo7.say();
    System.out.println(demo7.add());
  }
  public void say() {
    System.out.println("你好啊");
  }
  public int add() {
      int i=1;
      int j=2;
    return i+j;
  }
}
复制代码


public interface Demo9 extends Demo8{
  void print(String name);
}
复制代码


一个类实现 一个接口,如果这个接口继承了另一个接口,那么这个类除了实现这个接口的所有方法以外,还要实现被继承的那个接口的所有方法:


public class Demo10 implements Demo9 {
public static void main(String[] args) {
  }
  @Override
  public void say() {
    // TODO Auto-generated method stub
  }
  @Override
  public int add() {
    // TODO Auto-generated method stub
    return 0;
  }
  @Override
  public void print(String name) {
    // TODO Auto-generated method stub
  }
}
复制代码


二、抽象类


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


抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。具有抽象方法的类一定为抽象类。


由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。


父类包含了子类集合的常见的方法,但是由于父类本身是抽象的,所以不能使用这些方法。


在Java中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。


抽象类用来描述一种类型应该具备的基本特征与功能, 具体如何去完成这些行为由子类通过方法重写来完成,这点与接口很像,所以它们会被作为一类的面试题进行考察如:


猫科均会吼叫,但属于猫科的猫与老虎、豹子等它们吼叫的声音确实不同。所以猫科这就是一个类,它只规定了猫科这类的动物有吼叫功能,但并不明确吼叫的细节,吼叫的细节的内容应该由猫与老虎这样的猫科子类重写吼叫的方法具体实现。


即抽象方法指只有功能声明,没有功能主体实现的方法,与接口中的方法类似,但是抽象方法中除了可以有抽象方法还可以有具体的方法。


抽象类的实例:


public abstract class Demo11 {
     private String name;
     private String address;
     private int number;
     public Demo11(String name, String address, int number)
     {
        System.out.println("Constructing an Employee");
        this.name = name;
        this.address = address;
        this.number = number;
     }
     public double computePay()
     {
       System.out.println("Inside Employee computePay");
       return 0.0;
     }
     public void mailCheck()
     {
        System.out.println("Mailing a check to " + this.name
         + " " + this.address);
     }
     public String toString()
     {
        return name + " " + address + " " + number;
     }
     public String getName()
     {
        return name;
     }
     public String getAddress()
     {
        return address;
     }
     public void setAddress(String newAddress)
     {
        address = newAddress;
     }
     public int getNumber()
     {
       return number;
     }
}
复制代码


可以看到尽管该类是抽象类,但是它仍然有 3 个成员变量,7 个成员方法和 1 个构造方法。但是如果想实例化该类,则会报错:提示不能实例化Demo11


微信截图_20220519064501.png


微信截图_20220519064516.png


所以抽象类只能通过被继承:


public class Demo12 extends Demo11
{
     private double salary; //Annual salary
     public Demo12(String name, String address, int number, double
        salary)
     {
         super(name, address, number);
         setSalary(salary);
     }
     public void mailCheck()
     {
         System.out.println("Within mailCheck of Salary class ");
         System.out.println("Mailing check to " + getName()
         + " with salary " + salary);
     }
     public double getSalary()
     {
         return salary;
     }
     public void setSalary(double newSalary)
     {
         if(newSalary >= 0.0)
         {
            salary = newSalary;
         }
     }
     public double computePay()
     {
        System.out.println("Computing salary pay for " + getName());
        return salary/52;
     }
  }
复制代码


package Demo1;
public class Demo10 {
  public static void main(String[] args) {
      Demo12 demo12 = new Demo12("张三", "北京", 3, 3600.00);
        Demo11 demo11 = new Demo12("李四", "上海", 2, 2400.00);
        System.out.println("Call mailCheck using Salary reference --");
        demo12.mailCheck();
        System.out.println("\n Call mailCheck using Employee reference--");
        demo12.mailCheck();
  }
}
复制代码


网络异常,图片无法展示
|


所以尽管不能实例化一个抽象类,但是可以实例化一个继承了抽象类的子类,然后将抽象类的引用指向子类的对象。如果一个类中它拥有抽象方法,那么这个类就必须是抽象类,抽象类可以没有抽象方法,但是如果有抽象方法的类,必须被申明为抽象类。


public abstract class Demo11
{
   private String name;
   private String address;
   private int number;
   //抽象方法
   public abstract double computePay();
  }
复制代码


如果一个抽象类中有抽象方法,那么任何继承它的子类都必须重写父类的抽象方法,或者子类也可以声明自身为抽象类。但是最终,必须有子类实现该抽象方法,否则,从最初的父类到最终的子类都不能用来实例化对象,那么就没有任何的意义了。另外构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。


抽象类可实现接口,并且可以不实现接口中的方法,但是继承抽象类的实体类必须实现接口中的方法。


public abstract class Demo11 implements Demo9{
     private String name;
     private String address;
     private int number;
     public Demo11(String name, String address, int number)
     {
        System.out.println("Constructing an Employee");
        this.name = name;
        this.address = address;
        this.number = number;
     }
     public double computePay()
     {
       System.out.println("Inside Employee computePay");
       return 0.0;
     }
     public void mailCheck()
     {
        System.out.println("Mailing a check to " + this.name
         + " " + this.address);
     }
     public String toString()
     {
        return name + " " + address + " " + number;
     }
     public String getName()
     {
        return name;
     }
     public String getAddress()
     {
        return address;
     }
     public void setAddress(String newAddress)
     {
        address = newAddress;
     }
     public int getNumber()
     {
       return number;
     }
}
复制代码


17ac2b9f5bf0433da2fdc981dd898c9c~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


另外抽象类也可以继承实体类:


ebe905fe29d6418ca6a34c4ffa2eacbc~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


ff8f52bf3fa3446e8d86a03c9849dec0~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


抽象类中也可以有静态的main方法。


2bb0d09f303c4a96a4861a12715221bd~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


三、答案


所以我们可以总结一下这个问题的答案了:接口可以继承接口。抽象类可以实现(implements)接口,抽象类可以继承具体类。抽象类中可以有静态的main方法。

目录
相关文章
|
2月前
|
Java
接口和抽象类的区别
接口和抽象类的区别
32 6
|
2月前
|
Java
抽象类和接口有什么区别?
抽象类和接口有什么区别?
|
2月前
|
Java
抽象类和接口的区别
抽象类和接口的区别
39 0
|
11月前
接口和抽象类有什么区别
接口和抽象类有什么区别
48 0
|
12月前
抽象类和普通类的区别
抽象类和普通类的区别
91 0
|
12月前
|
Java C++
接口与抽象类的区别
接口与抽象类的区别
继承类的方法
继承类的方法
94 0
抽象类、接口的区别和相似点(一)
抽象类、接口的区别和相似点(一)
117 0
抽象类、接口的区别和相似点(一)
接口是否可继承(extends)接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concrete class)?
接口可以继承接口,而且支持多重继承。抽象类可以实现(implements)接口,抽象类可继承具体类也可以继承抽象类。
1878 0