java中抽象类的一些实际例子是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1509785/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 13:38:36  来源:igfitidea点击:

What are some practical examples of abstract classes in java?

javaoopabstract-class

提问by Click Upvote

When and why should abstract classes be used? I would like to see some practical examples of their uses. Also, what is the difference between abstract classes and interfaces?

何时以及为什么应该使用抽象类?我想看看它们用途的一些实际例子。另外,抽象类和接口有什么区别?

采纳答案by Blixt

Abstract classes are "half-implementations" of a class. They can be partially implemented with some generic functionality, but leave part of the implementation to the inheriting classes. You could have an abstract class called Animalthat has implemented some generic behavior/values such as Age, Name, SetAge(...). You can also have methods that are not implemented (they are abstract), much like an interface.

抽象类是类的“半实现”。它们可以通过一些通用功能部分实现,但将部分实现留给继承类。您可以有一个名为的抽象类Animal,它实现了一些通用行为/值,例如Age, Name, SetAge(...)。您还可以拥有未实现的方法(它们是abstract),就像接口一样。

Interfaces are simply contracts that specify behaviors that should be available for a class. You could have an interface such as IWalkerthat requires public method Walk(), but no specifics on how it is implemented.

接口只是简单的契约,它指定了一个类应该可用的行为。您可以拥有一个IWalker需要公共方法的接口Walk(),但没有具体说明它是如何实现的。

回答by Bart Kiers

http://java.sun.com/docs/books/tutorial/java/IandI/abstract.html

http://java.sun.com/docs/books/tutorial/java/IandI/abstract.html

http://java.sun.com/docs/books/tutorial/java/concepts/interface.html

http://java.sun.com/docs/books/tutorial/java/concepts/interface.html

In short, an abstract class can be partially implemented, an interface cannot. More details in the links above.

简而言之,抽象类可以部分实现,而接口则不能。在上面的链接中有更多详细信息。

回答by KLE

An interfacecontains no implementation at all.

一个接口包含所有没有实现。

An abstract classmay contain some implementation, that is useful to all subclasses, but not be complete : it needs to be completed in some way in the subclasses.
Where the interface lets you use polymorphism on several classes, abstract class also lets them reuse code.

一个抽象类可能包含一些对所有子类有用的实现,但不是完整的:它需要在子类中以某种方式完成。
接口允许您在多个类上使用多态性,抽象类还允许它们重用代码

     public abstract class Figure {
        protected Point position;

        public abstract void draw();
     }

     public class Square extends Figure {
       // position is usable

       public void draw() {
         // this method must be implemented, for Square not to be abstract
       }

       // here is other code
     }


Another difference is that a class can only have one superclass, but implements many interfaces. This can be a limiting factor.

另一个区别是一个类只能有一个超类,但实现了许多接口。这可能是一个限制因素。

回答by laura

Classes that are entirely abstract (all methods are abstract) are (almost) the same as interfaces (the major difference being they can contain fields and non-public abstract methods, which interfaces cannot). The difference is when you have an abstract class which contains a method which has some common functionality which will be the same for all derived children.

完全抽象的类(所有方法都是抽象的)(几乎)与接口相同(主要区别在于它们可以包含字段和非公共抽象方法,而接口不能)。不同之处在于,当您有一个抽象类时,该类包含一个具有一些通用功能的方法,这些功能对于所有派生子项都是相同的。

If you want to model a Filesystem, for example, you know that, regardless of the object type, you will have a path for an item. You'd want to have a common implementation for getting that path (no point in writing the same thing over and over again), and leave anything special for the children to implement.

例如,如果您想为文件系统建模,您知道,无论对象类型如何,您都将拥有项目的路径。您希望有一个通用的实现来获得该路径(一遍又一遍地编写相同的东西毫无意义),并为孩子们留下任何特殊的实现。

回答by sleske

As KLE correctly explained, the main difference between interface and abstract class is that an abstract class may contain fields and method bodies, while an interface may only contain method signatures (and constants, i.e. public static final fields).

正如 KLE 正确解释的那样,接口和抽象类之间的主要区别在于抽象类可能包含字段和方法体,而接口可能只包含方法签名(和常量,即公共静态最终字段)。

Another important distinction is that a class can implement multiple interfaces, but it can only (directly) inherit from one class (abstract or not). So for things which people will probably use in addition to other functionality, an interface makes more sense than an abstract class. See e.g. the interfaces Comparable in the JDK.

另一个重要的区别是一个类可以实现多个接口,但它只能(直接)从一个类(抽象与否)继承。因此,对于人们可能会在其他功能之外使用的东西,接口比抽象类更有意义。参见例如 JDK 中的接口 Comparable。

As an example:

举个例子:

In the system we develop, we have a class for starting a data import. We have many different kinds of data imports, but most have some things in common: They read data from a file, they write it to the database, they produce an import protocol etc.

在我们开发的系统中,我们有一个用于启动数据导入的类。我们有许多不同类型的数据导入,但大多数都有一些共同点:它们从文件中读取数据,将数据写入数据库,生成导入协议等。

So we have an abstract class "Import", which contains implemented methods for things like writing protocol entries, finding all files to import, deleting processed import files etc. The specifics will be different for each import, so there are abstract methods that serve as extension hooks, e.g. getFilenamePattern() which is used by the reading method to find the files that can be imported. getFilenamePattern is implemented in the concrete subclass, depending on what kinds of files need to be imported.

所以我们有一个抽象类“Import”,它包含了一些实现的方法,比如写协议条目、查找所有要导入的文件、删除处理过的导入文件等。每个导入的细节会有所不同,所以有抽象方法作为扩展钩子,例如 getFilenamePattern() 被读取方法用来查找可以导入的文件。getFilenamePattern 在具体的子类中实现,具体取决于需要导入的文件类型。

That way, the shared import functionality is in one place, while the specifics for one kind of import are separate.

这样,共享导入功能就在一个地方,而一种导入的细节是分开的。

回答by Uri

If you need to wrap your head around the concept of abstract classes, take a look at the Swing UI toolkit (or at AWT) in the standard library.

如果您需要了解抽象类的概念,请查看标准库中的 Swing UI 工具包(或 AWT)。

Because you can imagine what can be visualized (e.g., a button, a label), it's easy to contrast it with the things that can't be instantiated (e.g., a JComponent).

因为您可以想象可以可视化的内容(例如,按钮、标签),所以很容易将其与无法实例化的内容(例如,JComponent)进行对比。

回答by Pascal Thivent

Abstract Classes versus Interfaces

Unlike interfaces, abstract classes can contain fields that are not static and final, and they can contain implemented methods. Such abstract classes are similar to interfaces, except that they provide a partial implementation, leaving it to subclasses to complete the implementation. If an abstract class contains onlyabstract method declarations, it should be declared as an interface instead.

Multiple interfaces can be implemented by classes anywhere in the class hierarchy, whether or not they are related to one another in any way. Think of Comparableor Cloneable, for example.

By comparison, abstract classes are most commonly subclassed to share pieces of implementation. A single abstract class is subclassed by similar classes that have a lot in common (the implemented parts of the abstract class), but also have some differences (the abstract methods).

An Abstract Class Example

In an object-oriented drawing application, you can draw circles, rectangles, lines, Bezier curves, and many other graphic objects. These objects all have certain states (for example: position, orientation, line color, fill color) and behaviors (for example: moveTo, rotate, resize, draw) in common. Some of these states and behaviors are the same for all graphic objects—for example: position, fill color, and moveTo. Others require different implementations—for example, resize or draw. All GraphicObjectsmust know how to draw or resize themselves; they just differ in how they do it. This is a perfect situation for an abstract superclass. You can take advantage of the similarities and declare all the graphic objects to inherit from the same abstract parent object—for example, GraphicObject, as shown in the following figure.

Classes Rectangle, Line, Bezier, and Circle inherit from GraphicObject

Classes Rectangle, Line, Bezier, and Circle inherit from GraphicObject

[...]

抽象类与接口

与接口不同,抽象类可以包含非静态字段和final,并且它们可以包含已实现的方法。这种抽象类与接口类似,只是它们提供了部分实现,将其留给子类来完成实现。如果抽象类包含抽象方法声明,则应将其声明为接口。

多个接口可以由类层次结构中任何位置的类实现,无论它们是否以任何方式相互关联。例如,想想ComparableCloneable

相比之下,抽象类最常被子类化以共享实现。单个抽象类由具有很多共同点(抽象类的实现部分)但也有一些差异(抽象方法)的相似类进行子类化。

抽象类示例

在面向对象的绘图应用程序中,您可以绘制圆形、矩形、直线、贝塞尔曲线和许多其他图形对象。这些对象都具有某些共同的状态(例如:位置、方向、线条颜色、填充颜色)和行为(例如:moveTo、旋转、调整大小、绘制)。其中一些状态和行为对于所有图形对象都是相同的——例如:位置、填充颜色和移动到。其他的需要不同的实现——例如,调整大小或绘制。所有人都GraphicObjects必须知道如何绘制或调整自己的大小;他们只是在如何做到这一点上有所不同。这是抽象超类的完美情况。您可以利用这些相似性并将所有图形对象声明为从同一个抽象父对象继承——例如,GraphicObject,如下图所示。

Classes Rectangle, Line, Bezier, and Circle inherit from GraphicObject

类 Rectangle、Line、Bezier 和 Circle 继承自 GraphicObject

[...]

Source: The Java™ Tutorials

来源:Java™ 教程

回答by David Robles

You can restrict the order of execution of an instruction with specific steps, but allow delegation for the behavior of each step:

您可以限制具有特定步骤的指令的执行顺序,但允许委托每个步骤的行为:

public abstract class Instruction {

    void perform() {
        firstStep();
        secondStep();
        thirdStep();
    }

    abstract void firstStep();

    abstract void secondStep();

    abstract void thirdStep();

}

回答by Adriaan Koster

Surprisingly, many examples/explanations given here do not provide good arguments for using an abstract class. Merely putting common fields/methods in a superclass does not require it to be abstract. Also (start rant), shame on supposedly knowledgeable engineers still coming up with Animal / Vehicle / Figure hierarchies to 'explain' object oriented concepts. These types of examples are very misleading because they point you in the wrong direction; you generally should NOT favour straight subclassing because it creates a very tight coupling between the classes. Rather use collaboration (rant ends).

令人惊讶的是,这里给出的许多示例/解释并没有为使用抽象类提供很好的论据。仅仅将公共字段/方法放在超类中并不要求它是抽象的。另外(开始咆哮),对于那些据说知识渊博的工程师仍然提出动物/车辆/图形层次结构来“解释”面向对象的概念感到羞耻。这些类型的示例非常具有误导性,因为它们指向了错误的方向;您通常不应该支持直接子类化,因为它会在类之间创建非常紧密的耦合。而是使用协作(咆哮结束)。

So what do I think is a good use case for an abstract class? One of my favorite examples is an application of the 'template method' GoF pattern. Here you want to specify the generic flow of an algorithm once, but allow multiple implementations of the individual steps. Here an example I just put together of a VirusScanEngine containing the main virus scanning algorithm (find the next virus, either delete or report it, continue until scan is complete), and a LinearVirusScanner which implements the required algorithm steps (findVirus, deleteVirus and reportVirus). My apologies to all developers really working on virus scanning software for this horrendous simplification.

那么我认为抽象类的一个好的用例是什么?我最喜欢的例子之一是“模板方法”GoF 模式的应用。在这里,您希望一次指定算法的通用流程,但允许单个步骤的多个实现。这里有一个例子,我只是把一个包含主要病毒扫描算法的 VirusScanEngine(找到下一个病毒,删除或报告它,继续直到扫描完成)和一个实现所需算法步骤(findVirus、deleteVirus 和 reportVirus)的 LinearVirusScanner 放在一起)。对于这种可怕的简化,我向真正致力于病毒扫描软件的所有开发人员道歉。

import java.util.Arrays;

public abstract class VirusScanEngine {

    public static void main(String[] args) {

        byte[] memory = new byte[] { 'a', 'b', 'c', 'M', 'e', 'l', 'i', 's', 's',
                'a' , 'd', 'e', 'f', 'g'};
        System.out.println("Before: " + Arrays.toString(memory));
        new LinearVirusScanner().scan(memory, Action.DELETE);
        System.out.println("After: " + Arrays.toString(memory));
    }

    public enum Action {
        DELETE, REPORT
    };

    public boolean scan(byte[] memory, Action action) {

        boolean virusFound = false;
        int index = 0;
        while (index < memory.length) {

            int size = findVirus(memory, index);
            if (size > 0) {
                switch (action) {

                case DELETE:
                    deleteVirus(memory, index, size);
                    break;
                case REPORT:
                    reportVirus(memory, index, size);
                    break;
                }
                index += size;
            }
            index++;
        }
        return virusFound;
    }

    abstract int findVirus(byte[] memory, int startIndex);

    abstract void reportVirus(byte[] memory, int startIndex, int size);

    abstract void deleteVirus(byte[] memory, int startIndex, int size);
}

and

public class LinearVirusScanner extends VirusScanEngine {

    private static final byte[][] virusSignatures = new byte[][] {
            new byte[] { 'I', 'L', 'O', 'V', 'E', 'Y', 'O', 'U' },
            new byte[] { 'M', 'e', 'l', 'i', 's', 's', 'a' } };

    @Override
    int findVirus(byte[] memory, int startIndex) {

        int size = 0;
        signatures: for (int v = 0; v < virusSignatures.length; v++) {

            scan: {
                for (int t = 0; t < virusSignatures[v].length; t++) {

                    if (memory[startIndex + t] != virusSignatures[v][t]) {
                        break scan;
                    }
                }
                // virus found
                size = virusSignatures[v].length;
                break signatures;
            }
        }
        return size;
    }

    @Override
    void deleteVirus(byte[] memory, int startIndex, int size) {

        for (int n = startIndex; n < startIndex + size - 1; n++) {
            memory[n] = 0;
        }
    }

    @Override
    void reportVirus(byte[] memory, int startIndex, int size) {

        System.out.println("Virus found at position " + startIndex
                + " with length " + size);
    }
}

回答by James Drinkard

In my own thinking, the correct way is to approach this question is to determine the context you are dealing with regarding the domain or entity objects first, namely what is your use case?

在我自己的想法中,解决这个问题的正确方法是首先确定您正在处理的有关域或实体对象的上下文,即您的用例是什么?

In my personal experience, I do this using a top down and then bottom up approach. I start looking for inheritance by looking at the use case and seeing what classes I will need. Then I look to see if there is a superClassOrInterfaceType (since both classes and interfaces define types, I'm combining them into a one word for simplicity. Hopefully it doesn't make it more confusing) domain object that would encompass all the objects, as in a superClassOrInterfaceType of vehicle if I'm working on a use case dealing with subtypeClassOrInterfaceTypes like: cars, trucks, jeeps, and motorcycles for example. If there is a hierarchy relationship, then I define the superClassOrInterfaceType and subtypeClassOrInterfaceTypes.

根据我的个人经验,我使用自上而下然后自下而上的方法来做到这一点。我开始通过查看用例并查看我需要哪些类来寻找继承。然后我看看是否有一个 superClassOrInterfaceType(因为类和接口都定义了类型,为了简单起见,我将它们组合成一个词。希望它不会让它变得更加混乱)包含所有对象的域对象,就像在车辆的 superClassOrInterfaceType 中一样,如果我正在处理处理 subtypeClassOrInterfaceTypes 的用例,例如:汽车、卡车、吉普车和摩托车。如果存在层级关系,那么我定义了 superClassOrInterfaceType 和 subtypeClassOrInterfaceTypes。

As I said, what I generally do first is to look for a common domain superClassOrInterfaceType for the objects I'm dealing with. If so, I look for common method operations between the subtypeClassOrInterfaceTypes. If not, I look to see if there are common method implementations, because even though you may have a superClassOrInterfaceType and may have common methods, the implementations may not favor code reuse. At this point, if I have common methods, but no common implementations, I lean towards an interface. However, with this simplistic example, I should have some common methods with some common implementations between the vehicle subtypeClassOrInterfaceTypes that I can reuse code with.

正如我所说,我通常首先要做的是为我正在处理的对象寻找一个公共域 superClassOrInterfaceType。如果是这样,我会寻找 subtypeClassOrInterfaceTypes 之间的通用方法操作。如果没有,我会查看是否有通用方法实现,因为即使您可能有 superClassOrInterfaceType 并且可能有通用方法,但这些实现可能不利于代码重用。在这一点上,如果我有通用的方法,但没有通用的实现,我倾向于使用接口。然而,通过这个简单的例子,我应该有一些通用的方法,在车辆子类型类或接口类型之间有一些通用的实现,我可以重用代码。

On the other hand, if there is no inheritance structure, then I start from the bottom up to see if there are common methods. If there are no common methods and no common implementations, then I opt for a concrete class.

另一方面,如果没有继承结构,那我就从下往上开始,看看有没有通用的方法。如果没有通用的方法和通用的实现,那么我选择一个具体的类。

Generally, if there is inheritance with common methods and common implementations and a need for multiple subtype implementation methods in the same subtype, then I go with an abstract class, which is rare, but I do use it. If you just go with Abstract classes just because there is inheritance, you can run into problems if the code changes a lot. This is detailed very well in the example here: Interfaces vs Abstract Classes in Java, for the different types of domain objects of motors. One of them required a dual powered motor, that required multiple subtype implementation methods to be used in a single subtype class. In other words, a single class needed implementation methods from both solar powered and battery powered motors, which is modeling behaviors and not something you want to do with Abstract classes.

一般来说,如果有通用方法和通用实现的继承,并且需要在同一个子类型中有多个子类型实现方法,那么我会选择一个抽象类,这种情况很少见,但我确实使用了它。如果仅仅因为存在继承就使用抽象类,那么如果代码更改很多,您可能会遇到问题。在这里的示例中详细说明了这一点:Java 中的接口与抽象类,对于不同类型的电机域对象。其中之一需要双动力电机,这需要在单个子类型类中使用多个子类型实现方法。换句话说,单个类需要来自太阳能和电池供电的电机的实现方法,这是建模行为,而不是您想用抽象类做的事情。

To sum it all up, as a rule you want to define behaviors (what the objects will do) with interfaces and not in Abstract classes. Abstract classes focus on an implementation hierarchy and code reuse.

总而言之,作为一项规则,您希望使用接口而不是抽象类来定义行为(对象将做什么)。抽象类侧重于实现层次结构和代码重用。

Here are some links that go into greater details on this.

这里有一些链接,可以更详细地了解这一点。

Thanks Type & Gentle Class

谢谢类型和温和的类

The Magic behind Subtype Polymorphism

子类型多态背后的魔法

Maximize Flexibility with Interfaces & Abstract Classes

使用接口和抽象类最大化灵活性

Interfaces vs Abstract Classes in Java

Java 中的接口与抽象类