在我的一次采访中,我被要求解释接口类和抽象类之间的区别。

以下是我的回答:

Methods of a Java interface are implicitly abstract and cannot have implementations. A Java abstract class can have instance methods that implements a default behaviour. Variables declared in a Java interface are by default final. An abstract class may contain non-final variables. Members of a Java interface are public by default. A Java abstract class can have the usual flavours of class members like private, protected, etc. A Java interface should be implemented using keyword “implements”; A Java abstract class should be extended using keyword “extends”. An interface can extend another Java interface only, an abstract class can extend another Java class and implement multiple Java interfaces. A Java class can implement multiple interfaces but it can extend only one abstract class.

然而,面试官并不满意,他告诉我这种描述代表了“书本知识”。

他让我给出一个更实际的回答,用实际的例子解释我什么时候会选择抽象类而不是接口。

我哪里错了?


当前回答

嗯,现在人们渴望实用的方法,你说得很对,但大多数面试官看起来是按照他们目前的要求,想要一个实用的方法。

回答完你的问题后,你应该跳到例子上:

文摘:

例如,我们有一个工资函数,它有一些对所有员工共同的参数。然后我们可以有一个叫做CTC的抽象类,它带有部分定义的方法体,它将被所有类型的员工扩展,并根据他们的额外工资得到补偿。 对于公共功能。

public abstract class CTC {

    public int salary(int hra, int da, int extra)
    {
        int total;
        total = hra+da+extra;
        //incentive for specific performing employee
        //total = hra+da+extra+incentive;
        return total;
    }
}

class Manger extends CTC
{
}


class CEO extends CTC
{
}

class Developer extends CTC
{   
}

接口

Java中的接口允许在不扩展接口功能的情况下拥有接口功能,你必须清楚你想在应用程序中引入的功能签名的实现。它会迫使你做出定义。 不同的功能。

public interface EmployeType {

    public String typeOfEmployee();
}

class ContarctOne implements EmployeType
{

    @Override
    public String typeOfEmployee() {
        return "contract";
    }

}

class PermanentOne implements EmployeType
{

    @Override
    public String typeOfEmployee() {
        return "permanent";
    }

}

通过将methgos定义为抽象类,你也可以对抽象类进行这样的强制活动,现在一个扩展抽象类的类仍然是抽象类,直到它覆盖抽象函数。

其他回答

接口是纯粹抽象的。我们在接口中没有任何实现代码。

抽象类包含方法及其实现。

点击这里观看接口和抽象类教程

下面是一个围绕Java 8的解释,试图展示抽象类和接口之间的关键区别,并涵盖Java助理考试所需的所有细节。

关键概念:

一个类只能扩展一个类,但它可以实现任意数量的接口 接口定义了类的功能,抽象类定义了它是什么 抽象类是类。它们不能被实例化,但在其他方面表现得像普通类 两者都可以有抽象方法和静态方法 接口可以有默认方法和静态final常量,也可以扩展其他接口 所有接口成员都是公共的(直到Java 9)

接口定义了类的功能,抽象类定义了它是什么

每罗迪格林:

接口通常用来描述一个类的能力,而不是它的中心标识,例如,一个Automobile类可能实现了可回收接口,它可以应用于许多不相关的对象。抽象类定义其后代的核心标识。如果你定义一个Dog抽象类,那么达尔马提亚的后代就是Dog,他们不仅仅是可狗的。

Pre Java 8, @Daniel Lerps的回答非常准确,接口就像实现类必须履行的契约。

现在,使用默认方法,它们更像一个Mixin,仍然执行契约,但也可以提供代码来完成这项工作。这使得接口可以接管抽象类的一些用例。

抽象类的意义在于它以抽象方法的形式缺少功能。如果一个类没有任何抽象行为(在不同类型之间变化),那么它可能是一个具体的类。

抽象类是类

下面是类的一些常规特性,这些特性在抽象类中是可用的,但在接口中是不可用的:

实例变量/非最终变量。因此…… 可以访问和修改对象状态的方法 私有/受保护成员(但请参阅Java 9的注释) 扩展抽象或具体类的能力 构造函数

关于抽象类需要注意的几点:

它们不可能是最终的(因为它们的全部目的是扩展) 扩展另一个抽象类的抽象类继承其所有抽象方法作为自己的抽象方法

抽象方法

抽象类和接口都可以有0到多个抽象方法。抽象方法:

是没有主体的方法签名(即没有{}) 在抽象类中必须用abstract关键字标记。在接口中,该关键字是不必要的 不能是私有的(因为它们需要由另一个类实现) 不能最终确定(因为他们还没有身体) 不能是静态的(因为原因)

还要注意:

抽象方法可以由同一类/接口中的非抽象方法调用 扩展抽象类或实现接口的第一个具体类必须为所有抽象方法提供实现

静态方法

抽象类上的静态方法可以直接使用MyAbstractClass.method()调用;(例如,就像一个普通的类,它也可以通过一个扩展抽象类的类来调用)。

接口也可以有静态方法。它们只能通过接口的名称来调用(MyInterface.method();)。这些方法:

不能是抽象的,即必须有一个主体(参见上面的“因为原因”) 不是默认值(见下文)

默认的方法

接口可以有默认方法,该方法必须有default关键字和方法体。这些方法只能引用其他接口方法(不能引用特定实现的状态)。这些方法:

不是静止的 不是抽象的(他们有一个主体) 不能为最终值(名称“default”表示它们可能被覆盖)

如果一个类实现了两个具有相同签名的缺省方法的接口,则会导致编译错误,这可以通过覆盖该方法来解决。

接口可以有静态的final常量

接口只能包含上面描述的方法类型或常量。

常量被假定为静态的和最终的,并且可以在实现接口的类中不加限制地使用。

所有接口成员都是公共的

在Java 8中,接口的所有成员(以及接口本身)都被假定为公共的,不能被保护或私有(但Java 9确实允许接口中的私有方法)。

这意味着实现接口的类必须定义具有公共可见性的方法(与常规规则一致,方法不能被低可见性覆盖)。

我所观察到的主要区别是抽象类为我们提供了一些已经实现的常见行为,而子类只需要实现与它们对应的特定功能。而接口只指定需要完成哪些任务,接口不会给出任何实现。我可以说它指定了它自己和实现的类之间的契约。

简而言之,我想这样回答:

通过类层次结构进行继承意味着状态继承; 而通过接口继承则代表行为继承;

抽象类可以被视为介于这两种情况之间的东西(它引入了一些状态,但也迫使你定义一个行为),完全抽象类是一个接口(据我所知,这是c++中仅由虚拟方法组成的类的进一步发展)。

当然,从Java 8开始,事情发生了轻微的变化,但思想仍然是一样的。

我想这对于一个典型的Java面试来说已经足够了,如果你不是被编译器团队面试的话。

我先给大家举个例子:

public interface LoginAuth{
   public String encryptPassword(String pass);
   public void checkDBforUser();
}

假设您的应用程序中有3个数据库。然后,该数据库的每个实现都需要定义上述2个方法:

public class DBMySQL implements LoginAuth{
          // Needs to implement both methods
}
public class DBOracle implements LoginAuth{
          // Needs to implement both methods
}
public class DBAbc implements LoginAuth{
          // Needs to implement both methods
}

但是,如果encryptPassword()不依赖于数据库,并且对每个类都是相同的呢?那么上面的方法就不是一个好的方法。

相反,考虑以下方法:

public abstract class LoginAuth{
   public String encryptPassword(String pass){
            // Implement the same default behavior here 
            // that is shared by all subclasses.
   }

   // Each subclass needs to provide their own implementation of this only:
   public abstract void checkDBforUser();
}

现在,在每个子类中,我们只需要实现一个方法——依赖于数据库的方法。