Java中的抽象类与接口

时间:2022-07-10 15:40:02

I was asked a question, I wanted to get my answer reviewed here.

我被问到一个问题,我想在这里查看我的答案。

Q: In which scenario it is more appropriate to extend an abstract class rather than implementing the interface(s)?

问:在哪种情况下扩展抽象类而不是实现接口更合适?

A: If we are using template method design pattern.

答:如果我们使用模板方法设计模式。

Am I correct ?

我对么 ?

I am sorry if I was not able to state the question clearly.
I know the basic difference between abstract class and interface.

如果我无法清楚地陈述问题,我很抱歉。我知道抽象类和接口之间的基本区别。

1) use abstract class when the requirement is such that we need to implement the same functionality in every subclass for a specific operation (implement the method) and different functionality for some other operations (only method signatures)

1)当需求需要在特定操作的每个子类中实现相同的功能(实现方法)和其他一些操作的不同功能(仅方法签名)时,使用抽象类

2) use interface if you need to put the signature to be same (and implementation different) so that you can comply with interface implementation

2)如果需要将签名设置为相同(并且实现不同),则使用接口,以便您可以遵守接口实现

3) we can extend max of one abstract class, but can implement more than one interface

3)我们可以扩展一个抽象类的最大值,但可以实现多个接口

Reiterating the question: Are there any other scenarios, besides those mentioned above, where specifically we require to use abstract class (one is see is template method design pattern is conceptually based on this only)?

重申一个问题:除了上面提到的那些之外,还有其他任何场景,具体我们需要使用抽象类(一个是模板方法设计模式在概念上仅基于此)吗?

Interface vs. Abstract class

接口与抽象类

Choosing between these two really depends on what you want to do, but luckily for us, Erich Gamma can help us a bit.

在这两者之间做出选择真的取决于你想做什么,但幸运的是,对我们来说,Erich Gamma可以帮助我们一点。

As always there is a trade-off, an interface gives you freedom with regard to the base class, an abstract class gives you the freedom to add new methods later. – Erich Gamma

一如既往地存在权衡,接口为您提供基类的*,抽象类使您可以*地在以后添加新方法。 - Erich Gamma

You can’t go and change an Interface without having to change a lot of other things in your code, so the only way to avoid this would be to create a whole new Interface, which might not always be a good thing.

您无法在不更改代码中的许多其他内容的情况下更改接口,因此避免这种情况的唯一方法是创建一个全新的接口,这可能并不总是一件好事。

Abstract classes should primarily be used for objects that are closely related. Interfaces are better at providing common functionality for unrelated classes.

抽象类应主要用于密切相关的对象。接口更好地为不相关的类提供通用功能。

14 个解决方案

#1


67  

When To Use Interfaces

何时使用接口

An interface allows somebody to start from scratch to implement your interface or implement your interface in some other code whose original or primary purpose was quite different from your interface. To them, your interface is only incidental, something that have to add on to the their code to be able to use your package. The disadvantage is every method in the interface must be public. You might not want to expose everything.

界面允许某人从头开始实现您的界面或在其他原始或主要用途与您的界面完全不同的其他代码中实现您的界面。对他们来说,您的界面只是偶然的,必须添加到他们的代码才能使用您的包。缺点是界面中的每个方法都必须是公共的。你可能不想暴露一切。

When To Use Abstract classes

何时使用抽象类

An abstract class, in contrast, provides more structure. It usually defines some default implementations and provides some tools useful for a full implementation. The catch is, code using it must use your class as the base. That may be highly inconvenient if the other programmers wanting to use your package have already developed their own class hierarchy independently. In Java, a class can inherit from only one base class.

相比之下,抽象类提供了更多结构。它通常定义一些默认实现,并提供一些对完整实现有用的工具。问题是,使用它的代码必须使用您的类作为基础。如果其他想要使用您的包的程序员已经独立开发了自己的类层次结构,那么这可能会非常不方便。在Java中,类只能从一个基类继承。

When to Use Both

何时使用两者

You can offer the best of both worlds, an interface and an abstract class. Implementors can ignore your abstract class if they choose. The only drawback of doing that is calling methods via their interface name is slightly slower than calling them via their abstract class name.

您可以提供两全其美,界面和抽象类。如果选择,实现者可以忽略您的抽象类。这样做的唯一缺点是通过其接口名称调用方法比通过其抽象类名称调用方法稍慢。

#2


23  

reiterating the question: there is any other scenario besides these mentioned above where specifically we require to use abstract class (one is see is template method design pattern is conceptually based on this only)

重申一个问题:除了上面提到的这些还有其他任何情况我们需要使用抽象类(一个是模板方法设计模式在概念上仅基于此)

Yes, if you use JAXB. It does not like interfaces. You should either use abstract classes or work around this limitation with generics.

是的,如果你使用JAXB。它不喜欢接口。您应该使用抽象类或使用泛型来解决此限制。

From a personal blog post:

来自个人博客文章:

Interface:

接口:

  1. A class can implement multiple interfaces
  2. 一个类可以实现多个接口
  3. An interface cannot provide any code at all
  4. 接口根本无法提供任何代码
  5. An interface can only define public static final constants
  6. 接口只能定义公共静态最终常量
  7. An interface cannot define instance variables
  8. 接口无法定义实例变量
  9. Adding a new method has ripple effects on implementing classes (design maintenance)
  10. 添加新方法会对实现类产生连锁反应(设计维护)
  11. JAXB cannot deal with interfaces
  12. JAXB无法处理接口
  13. An interface cannot extends or implement an abstract class
  14. 接口不能扩展或实现抽象类
  15. All interface methods are public
  16. 所有接口方法都是公共的

In general, interfaces should be used to define contracts (what is to be achieved, not how to achieve it).

通常,接口应该用于定义合同(要实现的是什么,而不是如何实现它)。

Abstract Class:

抽象类:

  1. A class can extend at most one abstract class
  2. 一个类最多可以扩展一个抽象类
  3. An abstract class can contain code
  4. 抽象类可以包含代码
  5. An abstract class can define both static and instance constants (final)
  6. 抽象类可以定义静态和实例常量(最终)
  7. An abstract class can define instance variables
  8. 抽象类可以定义实例变量
  9. Modification of existing abstract class code has ripple effects on extending classes (implementation maintenance)
  10. 对现有抽象类代码的修改会对扩展类产生连锁反应(实现维护)
  11. Adding a new method to an abstract class has no ripple effect on extending classes
  12. 向抽象类添加新方法对扩展类没有连锁反应
  13. An abstract class can implement an interface
  14. 抽象类可以实现接口
  15. Abstract classes can implement private and protected methods
  16. 抽象类可以实现私有和受保护的方法

Abstract classes should be used for (partial) implementation. They can be a mean to restrain the way API contracts should be implemented.

抽象类应该用于(部分)实现。它们可以成为限制API合同实施方式的手段。

#3


9  

Interface is used when you have scenario that all classes has same structure but totally have different functionality.

当您拥有所有类具有相同结构但完全具有不同功能的场景时,将使用接口。

Abstract class is used when you have scenario that all classes has same structure but some same and some different functionality.

当您拥有所有类具有相同结构但具有相同且不同功能的场景时,将使用抽象类。

Take a look the article : http://shoaibmk.blogspot.com/2011/09/abstract-class-is-class-which-cannot-be.html

看一下这篇文章:http://shoaibmk.blogspot.com/2011/09/abstract-class-is-class-which-cannot-be.html

#4


4  

You are not correct. There are many scenarios. It just isn't possible to reduce it to a single 8-word rule.

你不对。有很多场景。它不可能将其减少为单个8字规则。

#5


4  

Which should you use, abstract classes or interfaces?

你应该使用哪些,抽象类或接口?

Consider using abstract classes if any of these statements apply to your scenario:

如果任何这些语句适用于您的场景,请考虑使用抽象类:

You want to share code among several closely related classes.

您希望在几个密切相关的类之间共享代码。

You expect that classes that extend your abstract class have many common methods or fields, or require access modifiers other than public (such as protected and private).

您希望扩展抽象类的类具有许多常用方法或字段,或者需要除公共之外的访问修饰符(例如protected和private)。

You want to declare non-static or non-final fields. This enables you to define methods that can access and modify the state of the object to which they belong.

您想声明非静态或非最终字段。这使您可以定义可以访问和修改它们所属对象的状态的方法。

Consider using interfaces if any of these statements apply to your situation:

如果任何这些语句适用于您的情况,请考虑使用接口:

You expect that unrelated classes would implement your interface. For example, the interfaces Comparable and Cloneable are implemented by many unrelated classes.

您希望不相关的类将实现您的接口。例如,Comparable和Cloneable接口由许多不相关的类实现。

You want to specify the behavior of a particular data type, but not concerned about who implements its behavior.

您希望指定特定数据类型的行为,但不关心谁实现其行为。

You want to take advantage of multiple inheritance of type.

您希望利用类型的多重继承。

http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html

http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html

#6


3  

In my opinion , the basic difference is that an interface can't contain non abstract methods while an abstract class can. So if subclasses share a common behaviour, this behaviour can be implemented in the super class and thus inherited in the subclasses

在我看来,基本的区别是接口不能包含非抽象方法,而抽象类可以。因此,如果子类共享一个共同的行为,则此行​​为可以在超类中实现,因此可以在子类中继承

Also I quoted the following from "software architecture design ppatterns in java" book

我还引用了“软件架构设计ppatterns in java”一书中的以下内容

" In the Java programming language there is no support for multiple inheritance. That means a class can inherit only from one single class. Hence inheritance should be used only when it is absolutely necessary. Whenever possible, methods denoting the common behavior should be declared in the form of a Java interface to be implemented by different implementer classes. But interfaces suffer from the limitation that they cannot provide method implementations. This means that every implementer of an interface must explicitly implement all methods declared in an interface, even when some of these methods represent the invariable part of the functionality and have exactly the same implementation in all of the implementer classes. This leads to redundant code. The following example demonstrates how the Abstract Parent Class pattern can be used in such cases without requiring redundant method implementations."

“在Java编程语言中,不支持多重继承。这意味着一个类只能从一个单独的类继承。因此只有在绝对必要的情况下才应该使用继承。只要有可能,就应该声明表示共同行为的方法。由不同的实现者类实现的Java接口的形式。但接口受到限制,他们无法提供方法实现。这意味着接口的每个实现者必须显式实现接口中声明的所有方法,即使其中一些方法代表功能的不变部分,并且在所有实现者类中具有完全相同的实现。这导致冗余代码。下面的示例演示了如何在这种情况下使用抽象父类模式而不需要冗余的方法实现。

#7


3  

Things have been changed a lot in last three years with addition of new capabilities to interface with Java 8 release.

在过去的三年里,随着Java 8版本的新功能的增加,情况发生了很大的变化。

From oracle documentation page on interface:

从界面上的oracle文档页面:

An interface is a reference type, similar to a class, that can contain only constants, method signatures, default methods, static methods, and nested types. Method bodies exist only for default methods and static methods.

接口是一种类似于类的引用类型,它只能包含常量,方法签名,默认方法,静态方法和嵌套类型。方法体仅适用于默认方法和静态方法。

As you quoted in your question, abstract class is best fit for template method pattern where you have to create skeleton. Interface cant be used here.

正如您在问题中引用的那样,抽象类最适合模板方法模式,您必须创建骨架。接口不能在这里使用。

One more consideration to prefer abstract class over interface:

更喜欢抽象类而不是接口的另一个考虑因素:

You don't have implementation in base class and only sub-classes have to define their own implementation. You need abstract class instead of interface since you want to share state with sub-classes.

您没有在基类中实现,只有子类必须定义自己的实现。您需要抽象类而不是接口,因为您希望与子类共享状态。

Abstract class establishes "is a" relation between related classes and interface provides "has a" capability between unrelated classes.

抽象类在相关类之间建立“是一种”关系,并且接口在不相关的类之间提供“具有”的能力。


Regarding second part of your question, which is valid for most of the programming languages including java prior to java-8 release

关于你的问题的第二部分,它对大多数编程语言都有效,包括java-8发布之前的java

As always there is a trade-off, an interface gives you freedom with regard to the base class, an abstract class gives you the freedom to add new methods later. – Erich Gamma

一如既往地存在权衡,接口为您提供基类的*,抽象类使您可以*地在以后添加新方法。 - Erich Gamma

You can’t go and change an Interface without having to change a lot of other things in your code

您无法更改界面而无需更改代码中的许多其他内容

If you prefer abstract class to interface earlier with above two considerations, you have to re-think now as default methods have added powerful capabilities to interfaces.

如果您更喜欢使用抽象类来与之前的两个注意事项进行交互,那么您必须重新思考,因为默认方法已经为接口添加了强大的功能。

Default methods enable you to add new functionality to the interfaces of your libraries and ensure binary compatibility with code written for older versions of those interfaces.

默认方法使您能够向库的接口添加新功能,并确保与为这些接口的旧版本编写的代码的二进制兼容性。

To select one of them between interface and abstract class, oracle documentation page quote that:

要在接口和抽象类之间选择其中一个,oracle文档页面引用:

Abstract classes are similar to interfaces. You cannot instantiate them, and they may contain a mix of methods declared with or without an implementation. However, with abstract classes, you can declare fields that are not static and final, and define public, protected, and private concrete methods.

抽象类与接口类似。您无法实例化它们,并且它们可能包含使用或不使用实现声明的混合方法。但是,使用抽象类,您可以声明非静态和最终的字段,并定义public,protected和private具体方法。

With interfaces, all fields are automatically public, static, and final, and all methods that you declare or define (as default methods) are public. In addition, you can extend only one class, whether or not it is abstract, whereas you can implement any number of interfaces.

使用接口,所有字段都自动为public,static和final,并且您声明或定义的所有方法(作为默认方法)都是公共的。此外,您只能扩展一个类,无论它是否是抽象的,而您可以实现任意数量的接口。

Refer to these related questions fore more details:

有关详细信息,请参阅这些相关问题:

Interface vs Abstract Class (general OO)

接口与抽象类(通用OO)

How should I have explained the difference between an Interface and an Abstract class?

我该如何解释Interface和Abstract类之间的区别?

In summary : The balance is tilting more towards interfaces now.

总结:现在,平衡更倾向于接口。

Are there any other scenarios, besides those mentioned above, where specifically we require to use abstract class (one is see is template method design pattern is conceptually based on this only)?

是否有任何其他场景,除了上面提到的那些,具体我们需要使用抽象类(一个是看模板方法设计模式在概念上仅基于此)?

Some design patterns use abstract classes (over interfaces) apart from Template method pattern.

除了Template方法模式之外,一些设计模式使用抽象类(在接口上)。

Creational patterns:

创作模式:

Abstract_factory_pattern

Abstract_factory_pattern

Structural patterns:

结构模式:

Decorator_pattern

Decorator_pattern

Behavioral patterns:

行为模式:

Mediator_pattern

Mediator_pattern

#8


2  

Abstract classes are different from interfaces in two important aspects

抽象类在两个重要方面与接口不同

  • they provide default implementation for chosen methods (that is covered by your answer)
  • 它们为所选方法提供默认实现(由您的答案涵盖)
  • abstract classes can have state (instance variables) - so this is one more situation you want to use them in place of interfaces
  • 抽象类可以有状态(实例变量) - 所以这是你想用它们代替接口的另一种情况

#9


2  

The shortest answer is, extend abstract class when some of the functionalities uou seek are already implemented in it.

最简单的答案是,当你所寻求的某些功能已经在其中实现时,扩展抽象类。

If you implement the interface you have to implement all the method. But for abstract class number of methods you need to implement might be fewer.

如果实现接口,则必须实现所有方法。但是对于抽象类,您需要实现的方法数量可能更少。

In template design pattern there must be a behavior defined. This behavior depends on other methods which are abstract. By making sub class and defining those methods you actually define the main behavior. The underlying behavior can not be in a interface as interface does not define anything, it just declares. So a template design pattern always comes with an abstract class. If you want to keep the flow of the behavior intact you must extend the abstract class but don't override the main behavior.

在模板设计模式中,必须定义一个行为。此行为取决于其他抽象方法。通过创建子类并定义这些方法,您实际上定义了主要行为。基础行为不能在接口中,因为接口没有定义任何东西,它只是声明。因此,模板设计模式总是带有抽象类。如果要保持行为的流程完整,则必须扩展抽象类,但不要覆盖主要行为。

#10


2  

There are a lot of great answers here, but I often find using BOTH interfaces and abstract classes is the best route. Consider this contrived example:

这里有很多很棒的答案,但我经常发现使用BOTH接口和抽象类是最好的选择。考虑这个人为的例子:

You're a software developer at an investment bank, and need to build a system that places orders into a market. Your interface captures the most general idea of what a trading system does,

您是投资银行的软件开发人员,需要建立一个将订单投入市场的系统。您的界面捕获了交易系统所做的最全面的概念,

1) Trading system places orders
2) Trading system receives acknowledgements

and can be captured in an interface, ITradeSystem

并且可以在界面ITradeSystem中捕获

public interface ITradeSystem{

     public void placeOrder(IOrder order);
     public void ackOrder(IOrder order);

}

Now engineers working at the sales desk and along other business lines can start to interface with your system to add order placement functionality to their existing apps. And you haven't even started building yet! This is the power of interfaces.

现在,在销售部门和其他业务部门工作的工程师可以开始与您的系统连接,以便为现有应用添加订单放置功能。而你还没有开始建设!这是接口的力量。

So you go ahead and build the system for stock traders; they've heard that your system has a feature to find cheap stocks and are very eager to try it out! You capture this behavior in a method called findGoodDeals(), but also realize there's a lot of messy stuff that's involved in connecting to the markets. For example, you have to open a SocketChannel,

所以你继续为股票交易者建立系统;他们听说你的系统有功能找到便宜的股票,非常渴望尝试一下!您在一个名为findGoodDeals()的方法中捕获此行为,但也意识到有很多混乱的东西涉及到连接市场。例如,您必须打开SocketChannel,

public class StockTradeSystem implements ITradeSystem{    

    @Override 
    public void placeOrder(IOrder order);
         getMarket().place(order);

    @Override 
    public void ackOrder(IOrder order);
         System.out.println("Order received" + order);    

    private void connectToMarket();
       SocketChannel sock = Socket.open();
       sock.bind(marketAddress); 
       <LOTS MORE MESSY CODE>
    }

    public void findGoodDeals();
       deals = <apply magic wizardry>
       System.out.println("The best stocks to buy are: " + deals);
    }

The concrete implementations are going to have lots of these messy methods like connectToMarket(), but findGoodDeals() is all the traders actually care about.

具体的实现将有很多这样的混乱方法,如connectToMarket(),但findGoodDeals()是所有交易者真正关心的。

Now here's where abstract classes come into play. Your boss informs you that currency traders also want to use your system. And looking at currency markets, you see the plumbing is nearly identical to stock markets. In fact, connectToMarket() can be reused verbatim to connect to foreign exchange markets. However, findGoodDeals() is a much different concept in the currency arena. So before you pass off the codebase to the foreign exchange wiz kid across the ocean, you first refactor into an abstract class, leaving findGoodDeals() unimplmented

现在这里是抽象类发挥作用的地方。你的老板告诉你货币交易者也想使用你的系统。看看货币市场,你会看到管道与股票市场几乎完全相同。实际上,connectToMarket()可以逐字重用,以连接到外汇市场。但是,findGoodDeals()在货币领域是一个非常不同的概念。因此,在将代码库传递给跨越海洋的外汇巫师之前,首先要重构为抽象类,让findGoodDeals()保持原样

public abstract class ABCTradeSystem implements ITradeSystem{    

    public abstract void findGoodDeals();

    @Override 
    public void placeOrder(IOrder order);
         getMarket().place(order);

    @Override 
    public void ackOrder(IOrder order);
         System.out.println("Order received" + order);    

    private void connectToMarket();
       SocketChannel sock = Socket.open();
       sock.bind(marketAddress); 
       <LOTS MORE MESSY CODE>
    }

Your stock trading system implements findGoodDeals() as you've already defined,

您的股票交易系统实现了您已经定义的findGoodDeals(),

public class StockTradeSystem extends ABCTradeSystem{    

    public void findGoodDeals();
       deals = <apply magic wizardry>
       System.out.println("The best stocks to buy are: " + deals);
    }

but now the FX whiz kid can build her system by simply providing an implementation of findGoodDeals() for currencies; she doesn't have to reimplement socket connections or even the interface methods!

但现在FX神童可以通过简单地为货币提供findGoodDeals()来实现她的系统;她不必重新实现套接字连接甚至接口方法!

public class CurrencyTradeSystem extends ABCTradeSystem{    

    public void findGoodDeals();
       ccys = <Genius stuff to find undervalued currencies>
       System.out.println("The best FX spot rates are: " + ccys);
    }

Programming to an interface is powerful, but similar applications often re-implement methods in nearly identical ways. Using an abstract class avoids reimplmentations, while preserving the power of the interface.

对接口进行编程非常强大,但类似的应用程序通常以几乎相同的方式重新实现方法。使用抽象类可以避免重新简化,同时保留接口的强大功能。

Note: one may wonder why findGreatDeals() isn't part of the interface. Remember, the interface defines the most general components of a trading system. Another engineer may develop a COMPLETELY DIFFERENT trading system, where they don't care about finding good deals. The interface guarantees that the sales desk can interface to their system as well, so it's preferable not to entangle your interface with application concepts like "great deals".

注意:有人可能想知道为什么findGreatDeals()不是接口的一部分。请记住,界面定义了交易系统的最常见组件。另一位工程师可能会开发一个完全不同的交易系统,他们不关心如何找到好的交易。界面保证了销售台也可以与他们的系统连接,因此最好不要将界面与“优惠”等应用程序概念纠缠在一起。

#11


1  

This is a good question The two of these are not similar but can be use for some of the same reason, like a rewrite. When creating it is best to use Interface. When it comes down to class, it is good for debugging.

这是一个很好的问题这两个不相似,但可以用于某些相同的原因,如重写。创建时最好使用Interface。在课堂上讲,这对调试很有帮助。

#12


0  

Abstract classes should be extended when you want to some common behavior to get extended. The Abstract super class will have the common behavior and will define abstract method/specific behavior which sub classes should implement.

当您想要扩展某些常见行为时,应该扩展抽象类。 Abstract超类将具有共同的行为,并将定义子类应实现的抽象方法/特定行为。

Interfaces allows you to change the implementation anytime allowing the interface to be intact.

接口允许您随时更改实现,从而允许接口完好无损。

#13


0  

This is my understanding, hope this helps

这是我的理解,希望对此有所帮助

Abstract classes:

抽象类:

  1. Can have member variables that are inherited (can’t be done in interfaces)
  2. 可以拥有继承的成员变量(不能在接口中完成)
  3. Can have constructors (interfaces can’t)
  4. 可以有构造函数(接口不能)
  5. Its methods can have any visibility (ie: private, protected, etc - whereas all interface methods are public)
  6. 它的方法可以具有任何可见性(即:私有,受保护等 - 而所有接口方法都是公共的)
  7. Can have defined methods (methods with an implementation)
  8. 可以有已定义的方法(带有实现的方法)

Interfaces:

接口:

  1. Can have variables, but they are all public static final variables
    • constant values that never change with a static scope
    • 永远不会随静态范围而变化的常量值
    • non static variables require an instance, and you can’t instantiate an interface
    • 非静态变量需要实例,并且您无法实例化接口
  2. 可以有变量,但它们都是公共静态最终变量常量值,永远不会随静态变量而变化非静态变量需要一个实例,并且你无法实例化一个接口
  3. All methods are abstract (no code in abstract methods)
    • all code has to be actually written in the class that implements the particular interface
    • 所有代码都必须实际编写在实现特定接口的类中
  4. 所有方法都是抽象的(抽象方法中没有代码)所有代码都必须实际编写在实现特定接口的类中

#14


0  

Usage of abstract and interface:

抽象和界面的用法:

One has "Is-A-Relationship" and another one has "Has-A-Relationship"

一个人有“是一个关系”而另一个有“有关系”

The default properties has set in abstract and extra properties can be expressed through interface.

默认属性已设置为abstract,并且可以通过接口表示其他属性。

Example: --> In the human beings we have some default properties that are eating, sleeping etc. but if anyone has any other curricular activities like swimming, playing etc those could be expressed by Interface.

例如: - >在人类中,我们有一些正在吃饭,睡觉等的默认属性,但如果有人有任何其他课程活动,如游泳,玩耍等,可以通过界面表达。

#1


67  

When To Use Interfaces

何时使用接口

An interface allows somebody to start from scratch to implement your interface or implement your interface in some other code whose original or primary purpose was quite different from your interface. To them, your interface is only incidental, something that have to add on to the their code to be able to use your package. The disadvantage is every method in the interface must be public. You might not want to expose everything.

界面允许某人从头开始实现您的界面或在其他原始或主要用途与您的界面完全不同的其他代码中实现您的界面。对他们来说,您的界面只是偶然的,必须添加到他们的代码才能使用您的包。缺点是界面中的每个方法都必须是公共的。你可能不想暴露一切。

When To Use Abstract classes

何时使用抽象类

An abstract class, in contrast, provides more structure. It usually defines some default implementations and provides some tools useful for a full implementation. The catch is, code using it must use your class as the base. That may be highly inconvenient if the other programmers wanting to use your package have already developed their own class hierarchy independently. In Java, a class can inherit from only one base class.

相比之下,抽象类提供了更多结构。它通常定义一些默认实现,并提供一些对完整实现有用的工具。问题是,使用它的代码必须使用您的类作为基础。如果其他想要使用您的包的程序员已经独立开发了自己的类层次结构,那么这可能会非常不方便。在Java中,类只能从一个基类继承。

When to Use Both

何时使用两者

You can offer the best of both worlds, an interface and an abstract class. Implementors can ignore your abstract class if they choose. The only drawback of doing that is calling methods via their interface name is slightly slower than calling them via their abstract class name.

您可以提供两全其美,界面和抽象类。如果选择,实现者可以忽略您的抽象类。这样做的唯一缺点是通过其接口名称调用方法比通过其抽象类名称调用方法稍慢。

#2


23  

reiterating the question: there is any other scenario besides these mentioned above where specifically we require to use abstract class (one is see is template method design pattern is conceptually based on this only)

重申一个问题:除了上面提到的这些还有其他任何情况我们需要使用抽象类(一个是模板方法设计模式在概念上仅基于此)

Yes, if you use JAXB. It does not like interfaces. You should either use abstract classes or work around this limitation with generics.

是的,如果你使用JAXB。它不喜欢接口。您应该使用抽象类或使用泛型来解决此限制。

From a personal blog post:

来自个人博客文章:

Interface:

接口:

  1. A class can implement multiple interfaces
  2. 一个类可以实现多个接口
  3. An interface cannot provide any code at all
  4. 接口根本无法提供任何代码
  5. An interface can only define public static final constants
  6. 接口只能定义公共静态最终常量
  7. An interface cannot define instance variables
  8. 接口无法定义实例变量
  9. Adding a new method has ripple effects on implementing classes (design maintenance)
  10. 添加新方法会对实现类产生连锁反应(设计维护)
  11. JAXB cannot deal with interfaces
  12. JAXB无法处理接口
  13. An interface cannot extends or implement an abstract class
  14. 接口不能扩展或实现抽象类
  15. All interface methods are public
  16. 所有接口方法都是公共的

In general, interfaces should be used to define contracts (what is to be achieved, not how to achieve it).

通常,接口应该用于定义合同(要实现的是什么,而不是如何实现它)。

Abstract Class:

抽象类:

  1. A class can extend at most one abstract class
  2. 一个类最多可以扩展一个抽象类
  3. An abstract class can contain code
  4. 抽象类可以包含代码
  5. An abstract class can define both static and instance constants (final)
  6. 抽象类可以定义静态和实例常量(最终)
  7. An abstract class can define instance variables
  8. 抽象类可以定义实例变量
  9. Modification of existing abstract class code has ripple effects on extending classes (implementation maintenance)
  10. 对现有抽象类代码的修改会对扩展类产生连锁反应(实现维护)
  11. Adding a new method to an abstract class has no ripple effect on extending classes
  12. 向抽象类添加新方法对扩展类没有连锁反应
  13. An abstract class can implement an interface
  14. 抽象类可以实现接口
  15. Abstract classes can implement private and protected methods
  16. 抽象类可以实现私有和受保护的方法

Abstract classes should be used for (partial) implementation. They can be a mean to restrain the way API contracts should be implemented.

抽象类应该用于(部分)实现。它们可以成为限制API合同实施方式的手段。

#3


9  

Interface is used when you have scenario that all classes has same structure but totally have different functionality.

当您拥有所有类具有相同结构但完全具有不同功能的场景时,将使用接口。

Abstract class is used when you have scenario that all classes has same structure but some same and some different functionality.

当您拥有所有类具有相同结构但具有相同且不同功能的场景时,将使用抽象类。

Take a look the article : http://shoaibmk.blogspot.com/2011/09/abstract-class-is-class-which-cannot-be.html

看一下这篇文章:http://shoaibmk.blogspot.com/2011/09/abstract-class-is-class-which-cannot-be.html

#4


4  

You are not correct. There are many scenarios. It just isn't possible to reduce it to a single 8-word rule.

你不对。有很多场景。它不可能将其减少为单个8字规则。

#5


4  

Which should you use, abstract classes or interfaces?

你应该使用哪些,抽象类或接口?

Consider using abstract classes if any of these statements apply to your scenario:

如果任何这些语句适用于您的场景,请考虑使用抽象类:

You want to share code among several closely related classes.

您希望在几个密切相关的类之间共享代码。

You expect that classes that extend your abstract class have many common methods or fields, or require access modifiers other than public (such as protected and private).

您希望扩展抽象类的类具有许多常用方法或字段,或者需要除公共之外的访问修饰符(例如protected和private)。

You want to declare non-static or non-final fields. This enables you to define methods that can access and modify the state of the object to which they belong.

您想声明非静态或非最终字段。这使您可以定义可以访问和修改它们所属对象的状态的方法。

Consider using interfaces if any of these statements apply to your situation:

如果任何这些语句适用于您的情况,请考虑使用接口:

You expect that unrelated classes would implement your interface. For example, the interfaces Comparable and Cloneable are implemented by many unrelated classes.

您希望不相关的类将实现您的接口。例如,Comparable和Cloneable接口由许多不相关的类实现。

You want to specify the behavior of a particular data type, but not concerned about who implements its behavior.

您希望指定特定数据类型的行为,但不关心谁实现其行为。

You want to take advantage of multiple inheritance of type.

您希望利用类型的多重继承。

http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html

http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html

#6


3  

In my opinion , the basic difference is that an interface can't contain non abstract methods while an abstract class can. So if subclasses share a common behaviour, this behaviour can be implemented in the super class and thus inherited in the subclasses

在我看来,基本的区别是接口不能包含非抽象方法,而抽象类可以。因此,如果子类共享一个共同的行为,则此行​​为可以在超类中实现,因此可以在子类中继承

Also I quoted the following from "software architecture design ppatterns in java" book

我还引用了“软件架构设计ppatterns in java”一书中的以下内容

" In the Java programming language there is no support for multiple inheritance. That means a class can inherit only from one single class. Hence inheritance should be used only when it is absolutely necessary. Whenever possible, methods denoting the common behavior should be declared in the form of a Java interface to be implemented by different implementer classes. But interfaces suffer from the limitation that they cannot provide method implementations. This means that every implementer of an interface must explicitly implement all methods declared in an interface, even when some of these methods represent the invariable part of the functionality and have exactly the same implementation in all of the implementer classes. This leads to redundant code. The following example demonstrates how the Abstract Parent Class pattern can be used in such cases without requiring redundant method implementations."

“在Java编程语言中,不支持多重继承。这意味着一个类只能从一个单独的类继承。因此只有在绝对必要的情况下才应该使用继承。只要有可能,就应该声明表示共同行为的方法。由不同的实现者类实现的Java接口的形式。但接口受到限制,他们无法提供方法实现。这意味着接口的每个实现者必须显式实现接口中声明的所有方法,即使其中一些方法代表功能的不变部分,并且在所有实现者类中具有完全相同的实现。这导致冗余代码。下面的示例演示了如何在这种情况下使用抽象父类模式而不需要冗余的方法实现。

#7


3  

Things have been changed a lot in last three years with addition of new capabilities to interface with Java 8 release.

在过去的三年里,随着Java 8版本的新功能的增加,情况发生了很大的变化。

From oracle documentation page on interface:

从界面上的oracle文档页面:

An interface is a reference type, similar to a class, that can contain only constants, method signatures, default methods, static methods, and nested types. Method bodies exist only for default methods and static methods.

接口是一种类似于类的引用类型,它只能包含常量,方法签名,默认方法,静态方法和嵌套类型。方法体仅适用于默认方法和静态方法。

As you quoted in your question, abstract class is best fit for template method pattern where you have to create skeleton. Interface cant be used here.

正如您在问题中引用的那样,抽象类最适合模板方法模式,您必须创建骨架。接口不能在这里使用。

One more consideration to prefer abstract class over interface:

更喜欢抽象类而不是接口的另一个考虑因素:

You don't have implementation in base class and only sub-classes have to define their own implementation. You need abstract class instead of interface since you want to share state with sub-classes.

您没有在基类中实现,只有子类必须定义自己的实现。您需要抽象类而不是接口,因为您希望与子类共享状态。

Abstract class establishes "is a" relation between related classes and interface provides "has a" capability between unrelated classes.

抽象类在相关类之间建立“是一种”关系,并且接口在不相关的类之间提供“具有”的能力。


Regarding second part of your question, which is valid for most of the programming languages including java prior to java-8 release

关于你的问题的第二部分,它对大多数编程语言都有效,包括java-8发布之前的java

As always there is a trade-off, an interface gives you freedom with regard to the base class, an abstract class gives you the freedom to add new methods later. – Erich Gamma

一如既往地存在权衡,接口为您提供基类的*,抽象类使您可以*地在以后添加新方法。 - Erich Gamma

You can’t go and change an Interface without having to change a lot of other things in your code

您无法更改界面而无需更改代码中的许多其他内容

If you prefer abstract class to interface earlier with above two considerations, you have to re-think now as default methods have added powerful capabilities to interfaces.

如果您更喜欢使用抽象类来与之前的两个注意事项进行交互,那么您必须重新思考,因为默认方法已经为接口添加了强大的功能。

Default methods enable you to add new functionality to the interfaces of your libraries and ensure binary compatibility with code written for older versions of those interfaces.

默认方法使您能够向库的接口添加新功能,并确保与为这些接口的旧版本编写的代码的二进制兼容性。

To select one of them between interface and abstract class, oracle documentation page quote that:

要在接口和抽象类之间选择其中一个,oracle文档页面引用:

Abstract classes are similar to interfaces. You cannot instantiate them, and they may contain a mix of methods declared with or without an implementation. However, with abstract classes, you can declare fields that are not static and final, and define public, protected, and private concrete methods.

抽象类与接口类似。您无法实例化它们,并且它们可能包含使用或不使用实现声明的混合方法。但是,使用抽象类,您可以声明非静态和最终的字段,并定义public,protected和private具体方法。

With interfaces, all fields are automatically public, static, and final, and all methods that you declare or define (as default methods) are public. In addition, you can extend only one class, whether or not it is abstract, whereas you can implement any number of interfaces.

使用接口,所有字段都自动为public,static和final,并且您声明或定义的所有方法(作为默认方法)都是公共的。此外,您只能扩展一个类,无论它是否是抽象的,而您可以实现任意数量的接口。

Refer to these related questions fore more details:

有关详细信息,请参阅这些相关问题:

Interface vs Abstract Class (general OO)

接口与抽象类(通用OO)

How should I have explained the difference between an Interface and an Abstract class?

我该如何解释Interface和Abstract类之间的区别?

In summary : The balance is tilting more towards interfaces now.

总结:现在,平衡更倾向于接口。

Are there any other scenarios, besides those mentioned above, where specifically we require to use abstract class (one is see is template method design pattern is conceptually based on this only)?

是否有任何其他场景,除了上面提到的那些,具体我们需要使用抽象类(一个是看模板方法设计模式在概念上仅基于此)?

Some design patterns use abstract classes (over interfaces) apart from Template method pattern.

除了Template方法模式之外,一些设计模式使用抽象类(在接口上)。

Creational patterns:

创作模式:

Abstract_factory_pattern

Abstract_factory_pattern

Structural patterns:

结构模式:

Decorator_pattern

Decorator_pattern

Behavioral patterns:

行为模式:

Mediator_pattern

Mediator_pattern

#8


2  

Abstract classes are different from interfaces in two important aspects

抽象类在两个重要方面与接口不同

  • they provide default implementation for chosen methods (that is covered by your answer)
  • 它们为所选方法提供默认实现(由您的答案涵盖)
  • abstract classes can have state (instance variables) - so this is one more situation you want to use them in place of interfaces
  • 抽象类可以有状态(实例变量) - 所以这是你想用它们代替接口的另一种情况

#9


2  

The shortest answer is, extend abstract class when some of the functionalities uou seek are already implemented in it.

最简单的答案是,当你所寻求的某些功能已经在其中实现时,扩展抽象类。

If you implement the interface you have to implement all the method. But for abstract class number of methods you need to implement might be fewer.

如果实现接口,则必须实现所有方法。但是对于抽象类,您需要实现的方法数量可能更少。

In template design pattern there must be a behavior defined. This behavior depends on other methods which are abstract. By making sub class and defining those methods you actually define the main behavior. The underlying behavior can not be in a interface as interface does not define anything, it just declares. So a template design pattern always comes with an abstract class. If you want to keep the flow of the behavior intact you must extend the abstract class but don't override the main behavior.

在模板设计模式中,必须定义一个行为。此行为取决于其他抽象方法。通过创建子类并定义这些方法,您实际上定义了主要行为。基础行为不能在接口中,因为接口没有定义任何东西,它只是声明。因此,模板设计模式总是带有抽象类。如果要保持行为的流程完整,则必须扩展抽象类,但不要覆盖主要行为。

#10


2  

There are a lot of great answers here, but I often find using BOTH interfaces and abstract classes is the best route. Consider this contrived example:

这里有很多很棒的答案,但我经常发现使用BOTH接口和抽象类是最好的选择。考虑这个人为的例子:

You're a software developer at an investment bank, and need to build a system that places orders into a market. Your interface captures the most general idea of what a trading system does,

您是投资银行的软件开发人员,需要建立一个将订单投入市场的系统。您的界面捕获了交易系统所做的最全面的概念,

1) Trading system places orders
2) Trading system receives acknowledgements

and can be captured in an interface, ITradeSystem

并且可以在界面ITradeSystem中捕获

public interface ITradeSystem{

     public void placeOrder(IOrder order);
     public void ackOrder(IOrder order);

}

Now engineers working at the sales desk and along other business lines can start to interface with your system to add order placement functionality to their existing apps. And you haven't even started building yet! This is the power of interfaces.

现在,在销售部门和其他业务部门工作的工程师可以开始与您的系统连接,以便为现有应用添加订单放置功能。而你还没有开始建设!这是接口的力量。

So you go ahead and build the system for stock traders; they've heard that your system has a feature to find cheap stocks and are very eager to try it out! You capture this behavior in a method called findGoodDeals(), but also realize there's a lot of messy stuff that's involved in connecting to the markets. For example, you have to open a SocketChannel,

所以你继续为股票交易者建立系统;他们听说你的系统有功能找到便宜的股票,非常渴望尝试一下!您在一个名为findGoodDeals()的方法中捕获此行为,但也意识到有很多混乱的东西涉及到连接市场。例如,您必须打开SocketChannel,

public class StockTradeSystem implements ITradeSystem{    

    @Override 
    public void placeOrder(IOrder order);
         getMarket().place(order);

    @Override 
    public void ackOrder(IOrder order);
         System.out.println("Order received" + order);    

    private void connectToMarket();
       SocketChannel sock = Socket.open();
       sock.bind(marketAddress); 
       <LOTS MORE MESSY CODE>
    }

    public void findGoodDeals();
       deals = <apply magic wizardry>
       System.out.println("The best stocks to buy are: " + deals);
    }

The concrete implementations are going to have lots of these messy methods like connectToMarket(), but findGoodDeals() is all the traders actually care about.

具体的实现将有很多这样的混乱方法,如connectToMarket(),但findGoodDeals()是所有交易者真正关心的。

Now here's where abstract classes come into play. Your boss informs you that currency traders also want to use your system. And looking at currency markets, you see the plumbing is nearly identical to stock markets. In fact, connectToMarket() can be reused verbatim to connect to foreign exchange markets. However, findGoodDeals() is a much different concept in the currency arena. So before you pass off the codebase to the foreign exchange wiz kid across the ocean, you first refactor into an abstract class, leaving findGoodDeals() unimplmented

现在这里是抽象类发挥作用的地方。你的老板告诉你货币交易者也想使用你的系统。看看货币市场,你会看到管道与股票市场几乎完全相同。实际上,connectToMarket()可以逐字重用,以连接到外汇市场。但是,findGoodDeals()在货币领域是一个非常不同的概念。因此,在将代码库传递给跨越海洋的外汇巫师之前,首先要重构为抽象类,让findGoodDeals()保持原样

public abstract class ABCTradeSystem implements ITradeSystem{    

    public abstract void findGoodDeals();

    @Override 
    public void placeOrder(IOrder order);
         getMarket().place(order);

    @Override 
    public void ackOrder(IOrder order);
         System.out.println("Order received" + order);    

    private void connectToMarket();
       SocketChannel sock = Socket.open();
       sock.bind(marketAddress); 
       <LOTS MORE MESSY CODE>
    }

Your stock trading system implements findGoodDeals() as you've already defined,

您的股票交易系统实现了您已经定义的findGoodDeals(),

public class StockTradeSystem extends ABCTradeSystem{    

    public void findGoodDeals();
       deals = <apply magic wizardry>
       System.out.println("The best stocks to buy are: " + deals);
    }

but now the FX whiz kid can build her system by simply providing an implementation of findGoodDeals() for currencies; she doesn't have to reimplement socket connections or even the interface methods!

但现在FX神童可以通过简单地为货币提供findGoodDeals()来实现她的系统;她不必重新实现套接字连接甚至接口方法!

public class CurrencyTradeSystem extends ABCTradeSystem{    

    public void findGoodDeals();
       ccys = <Genius stuff to find undervalued currencies>
       System.out.println("The best FX spot rates are: " + ccys);
    }

Programming to an interface is powerful, but similar applications often re-implement methods in nearly identical ways. Using an abstract class avoids reimplmentations, while preserving the power of the interface.

对接口进行编程非常强大,但类似的应用程序通常以几乎相同的方式重新实现方法。使用抽象类可以避免重新简化,同时保留接口的强大功能。

Note: one may wonder why findGreatDeals() isn't part of the interface. Remember, the interface defines the most general components of a trading system. Another engineer may develop a COMPLETELY DIFFERENT trading system, where they don't care about finding good deals. The interface guarantees that the sales desk can interface to their system as well, so it's preferable not to entangle your interface with application concepts like "great deals".

注意:有人可能想知道为什么findGreatDeals()不是接口的一部分。请记住,界面定义了交易系统的最常见组件。另一位工程师可能会开发一个完全不同的交易系统,他们不关心如何找到好的交易。界面保证了销售台也可以与他们的系统连接,因此最好不要将界面与“优惠”等应用程序概念纠缠在一起。

#11


1  

This is a good question The two of these are not similar but can be use for some of the same reason, like a rewrite. When creating it is best to use Interface. When it comes down to class, it is good for debugging.

这是一个很好的问题这两个不相似,但可以用于某些相同的原因,如重写。创建时最好使用Interface。在课堂上讲,这对调试很有帮助。

#12


0  

Abstract classes should be extended when you want to some common behavior to get extended. The Abstract super class will have the common behavior and will define abstract method/specific behavior which sub classes should implement.

当您想要扩展某些常见行为时,应该扩展抽象类。 Abstract超类将具有共同的行为,并将定义子类应实现的抽象方法/特定行为。

Interfaces allows you to change the implementation anytime allowing the interface to be intact.

接口允许您随时更改实现,从而允许接口完好无损。

#13


0  

This is my understanding, hope this helps

这是我的理解,希望对此有所帮助

Abstract classes:

抽象类:

  1. Can have member variables that are inherited (can’t be done in interfaces)
  2. 可以拥有继承的成员变量(不能在接口中完成)
  3. Can have constructors (interfaces can’t)
  4. 可以有构造函数(接口不能)
  5. Its methods can have any visibility (ie: private, protected, etc - whereas all interface methods are public)
  6. 它的方法可以具有任何可见性(即:私有,受保护等 - 而所有接口方法都是公共的)
  7. Can have defined methods (methods with an implementation)
  8. 可以有已定义的方法(带有实现的方法)

Interfaces:

接口:

  1. Can have variables, but they are all public static final variables
    • constant values that never change with a static scope
    • 永远不会随静态范围而变化的常量值
    • non static variables require an instance, and you can’t instantiate an interface
    • 非静态变量需要实例,并且您无法实例化接口
  2. 可以有变量,但它们都是公共静态最终变量常量值,永远不会随静态变量而变化非静态变量需要一个实例,并且你无法实例化一个接口
  3. All methods are abstract (no code in abstract methods)
    • all code has to be actually written in the class that implements the particular interface
    • 所有代码都必须实际编写在实现特定接口的类中
  4. 所有方法都是抽象的(抽象方法中没有代码)所有代码都必须实际编写在实现特定接口的类中

#14


0  

Usage of abstract and interface:

抽象和界面的用法:

One has "Is-A-Relationship" and another one has "Has-A-Relationship"

一个人有“是一个关系”而另一个有“有关系”

The default properties has set in abstract and extra properties can be expressed through interface.

默认属性已设置为abstract,并且可以通过接口表示其他属性。

Example: --> In the human beings we have some default properties that are eating, sleeping etc. but if anyone has any other curricular activities like swimming, playing etc those could be expressed by Interface.

例如: - >在人类中,我们有一些正在吃饭,睡觉等的默认属性,但如果有人有任何其他课程活动,如游泳,玩耍等,可以通过界面表达。