使用抽象方法有什么意义?

发布于 2024-12-19 11:39:52 字数 202 浏览 3 评论 0原文

使用“抽象方法”有什么意义?抽象类不能被实例化,但是抽象方法呢?它们只是在这里说“你必须实现我”,如果我们忘记它们,编译器会抛出错误吗?

难道还有别的意思吗?我还读过一些关于“我们不必重写相同的代码”的内容,但是在抽象类中,我们只“声明”抽象方法,因此我们必须重写子类中的代码。

你能帮我多理解一点吗?我检查了有关“抽象类/方法”的其他主题,但没有找到答案。

What's the point of using "abstract methods"? An abstract class cannot be instantiated, but what about the abstract methods? Are they just here to say "you have to implement me", and if we forget them, the compiler throws an error?

Does it mean something else? I also read something about "we don't have to rewrite the same code", but in the abstract class, we only "declare" the abstract method, so we will have to rewrite the code in the child class.

Can you help me understand it a bit more? I checked the other topics about "abstract class/methods" but I didn't find an answer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

权谋诡计 2024-12-26 11:39:52

假设您有三台打印机,需要为其编写驱动程序:LexmarkCanonHP

所有三台打印机都具有 print()getSystemResource() 方法。

但是,每台打印机的 print() 都会有所不同,并且 getSystemResource() 对于所有三台打印机保持相同。您还有另一个顾虑,您想应用多态性。

由于 getSystemResource() 对于所有三种打印机来说都是相同的,因此您可以将其推送到要实现的超类,并让子类实现 print()。在 Java 中,这是通过在超类中使 print() 抽象来完成的。注意:当在类中将方法抽象化时,类本身也需要是抽象的。

public abstract class Printer{
  public void getSystemResource(){
     // real implementation of getting system resources
  }
  
  public abstract void print();
}

public class Canon extends Printer{
  public void print(){
    // here you will provide the implementation of print pertaining to Canon
  }
}

public class HP extends Printer{
  public void print(){
    // here you will provide the implementation of print pertaining to HP
  }
}

public class Lexmark extends Printer{
  public void print(){
    // here you will provide the implementation of print pertaining to Lexmark
  }
}

请注意,HP、Canon 和 Lexmark 类不提供 getSystemResource() 的实现。

最后,在主类中,您可以执行以下操作:

public static void main(String args[]){
  Printer printer = new HP();
  printer.getSystemResource();
  printer.print();
}

Say you have three printers that you need to write drivers for, Lexmark, Canon, and HP.

All three printers will have the print() and getSystemResource() methods.

However, print() will be different for each printer, and getSystemResource() remains the same for all three printers. You also have another concern, you would like to apply polymorphism.

Since getSystemResource() is the same for all three printers, you can push this up to the super class to be implemented, and let the subclasses implement print(). In Java, this is done by making print() abstract in the super class. Note: when making a method abstract in a class, the class itself needs to be abstract as well.

public abstract class Printer{
  public void getSystemResource(){
     // real implementation of getting system resources
  }
  
  public abstract void print();
}

public class Canon extends Printer{
  public void print(){
    // here you will provide the implementation of print pertaining to Canon
  }
}

public class HP extends Printer{
  public void print(){
    // here you will provide the implementation of print pertaining to HP
  }
}

public class Lexmark extends Printer{
  public void print(){
    // here you will provide the implementation of print pertaining to Lexmark
  }
}

Notice that HP, Canon and Lexmark classes do not provide the implementation of getSystemResource().

Finally, in your main class, you can do the following:

public static void main(String args[]){
  Printer printer = new HP();
  printer.getSystemResource();
  printer.print();
}
醉生梦死 2024-12-26 11:39:52

除了提醒您必须实现它之外,最大的优点是任何通过抽象类类型(包括抽象类本身中的 this)引用该对象的人都可以使用该方法。

例如,假设我们有一个类负责获取状态并以某种方式操作它。抽象类将负责获取输入,将其转换为long(例如),并以某种方式将该值与先前的值组合起来——“某种方式”就是抽象方法。抽象类可能看起来像:

public abstract class StateAccumulator {
    protected abstract long accumulate(long oldState, long newState);

    public handleInput(SomeInputObject input) {
        long inputLong = input.getLong();
        state = accumulate(state, inputLong);
    }

    private long state = SOME_INITIAL_STATE;
}

现在您可以定义一个加法累加器:

public class AdditionAccumulator extends StateAccumulator {
    @Override
    protected long accumulate(long oldState, long newState) {
        return oldState + newState;
    }
}

如果没有该抽象方法,基类将无法说“以某种方式处理此状态”。不过,我们不想在基类中提供默认实现,因为这没有多大意义——如何为“其他人将实现这个”定义默认实现?

请注意,剥猫皮的方法不止一种。 策略模式将涉及声明一个声明accumulate模式的接口,并将该接口的实例传递给不再抽象的基类。用行话来说,这是使用组合而不是继承(您已经用两个对象(一个聚合器和一个加法器)组合了一个加法聚合器)。

Besides the reminder that you have to implement it, the big advantage is that anyone who references the object by its abstract class type (including this in the abstract class itself) can use the method.

For instance, let's say we have a class responsible for taking state and manipulating it in some way. The abstract class is going to be responsible for getting the input, converting it to a long (for instance) and combining that value with the previous value in some way -- that "some way" is the abstract method. The abstract class may look something like:

public abstract class StateAccumulator {
    protected abstract long accumulate(long oldState, long newState);

    public handleInput(SomeInputObject input) {
        long inputLong = input.getLong();
        state = accumulate(state, inputLong);
    }

    private long state = SOME_INITIAL_STATE;
}

Now you can define an addition accumulator:

public class AdditionAccumulator extends StateAccumulator {
    @Override
    protected long accumulate(long oldState, long newState) {
        return oldState + newState;
    }
}

Without that abstract method, the base class would have no way to say "handle this state somehow." We don't want to provide a default implementation in the base class, though, because it wouldn't mean much -- how do you define a default implementation for "someone else will implement this"?

Note that there's more than one way to skin a cat. The strategy pattern would involve declaring an interface that declares the accumulate pattern, and passing an instance of that interface to the no-longer-abstract base class. In lingo terms, that's using composition instead of inheritance (you've composed an addition aggregator out of two objects, an aggregator and an adder).

爱情眠于流年 2024-12-26 11:39:52

抽象类是包含一个或多个抽象方法的类。抽象方法是已声明但不包含实现的方法。抽象类不能被实例化,并且需要子类提供抽象方法的实现。让我们看一个抽象类和抽象方法的示例。

假设我们通过创建一个以名为 Animal 的基类开始的类层次结构来建模动物的行为。动物能够做不同的事情,比如飞行、挖掘和行走,但也有一些常见的操作,比如吃饭、睡觉和发出声音。所有动物都会执行一些常见的操作,但方式也不同。当以不同方式执行操作时,它是抽象方法的良好候选者(强制子类提供自定义实现)。让我们看一个非常原始的 Animal 基类,它定义了一个用于发出声音(例如狗叫、牛叫或猪叫)的抽象方法。

public abstract Animal {

public void sleep{
// sleeping time
}
public void eat(food)
{
//eat something
}
public abstract void makeNoise();
}
public Dog extends Animal {
 public void makeNoise() {
 System.out.println("Bark! Bark!");
 }
}
public Cow extends Animal {
 public void makeNoise() {
 System.out.println("Moo! Moo!");
 }
}

请注意,abstract 关键字用于表示抽象方法和抽象类。现在,任何想要实例化的动物(如狗或牛)都必须实现 makeNoise 方法 - 否则无法创建该类的实例。让我们看一下扩展 Animal 类的 Dog 和 Cow 子类。

现在您可能想知道为什么不将抽象类声明为接口,并让 Dog 和 Cow 实现该接口。当然可以 - 但您还需要实现 eat 和 sleep 方法。通过使用抽象类,您可以继承其他(非抽象)方法的实现。您不能使用接口来做到这一点 - 接口不能提供任何方法实现。

简而言之,接口应该包含所有抽象方法,但不包含方法的实现,或者我们不能在接口中定义非抽象方法,在接口中所有方法都应该是抽象的,但在抽象类中我们可以同时定义抽象方法和非抽象方法,所以为了定义非抽象方法,我们不必定义另一个类来实现同一对象的行为,这是抽象类相对于接口的优势。

Abstract classes are classes that contain one or more abstract methods. An abstract method is a method that is declared, but contains no implementation. Abstract classes may not be instantiated, and require subclasses to provide implementations for the abstract methods. Let's look at an example of an abstract class, and an abstract method.

Suppose we were modeling the behavior of animals, by creating a class hierachy that started with a base class called Animal. Animals are capable of doing different things like flying, digging and walking, but there are some common operations as well like eating and sleeping and making noise. Some common operations are performed by all animals, but in a different way as well. When an operation is performed in a different way, it is a good candidate for an abstract method (forcing subclasses to provide a custom implementation). Let's look at a very primitive Animal base class, which defines an abstract method for making a sound (such as a dog barking, a cow mooing, or a pig oinking).

public abstract Animal {

public void sleep{
// sleeping time
}
public void eat(food)
{
//eat something
}
public abstract void makeNoise();
}
public Dog extends Animal {
 public void makeNoise() {
 System.out.println("Bark! Bark!");
 }
}
public Cow extends Animal {
 public void makeNoise() {
 System.out.println("Moo! Moo!");
 }
}

Note that the abstract keyword is used to denote both an abstract method, and an abstract class. Now, any animal that wants to be instantiated (like a dog or cow) must implement the makeNoise method - otherwise it is impossible to create an instance of that class. Let's look at a Dog and Cow subclass that extends the Animal class.

Now you may be wondering why not declare an abstract class as an interface, and have the Dog and Cow implement the interface. Sure you could - but you'd also need to implement the eat and sleep methods. By using abstract classes, you can inherit the implementation of other (non-abstract) methods. You can't do that with interfaces - an interface cannot provide any method implementations.

In simple word an interface should contain all abstract method but no implementation of method or we can’t define non abstract method in interface, in interface all the method should be abstract but in abstract class we can define both abstract and non abstract method, so for defining non abstract method we don’t have to define another class to implement the behavior of same object this is the advantage of abstract class over interface.

只涨不跌 2024-12-26 11:39:52

抽象方法仅仅定义派生类必须实现的契约。这是您确保他们实际上始终会这样做的方式。

让我们以抽象类 Shape 为例。它将有一个应该绘制它的抽象方法draw()。 (Shape 是抽象的,因为我们不知道如何绘制一般形状)通过在 Shape 中使用抽象方法 draw,我们保证所有派生的类,实际上可以绘制,例如Circle就实现了draw。稍后,如果我们忘记在从 Shape 派生的某个类中实现 draw,编译器实际上会提供帮助并给出错误。

The abstract methods merely define a contract that derived classes must implement. It's is the way how you ensure that they actually always will.

So let's take for example an abstract class Shape. It would have an abstract method draw() that should draw it. (Shape is abstract, because we do not know how to draw a general shape) By having abstract method draw in Shape we guarantee that all derived classed, that actually can be drawn, for example Circle do implement draw. Later if we forget to implement draw in some class, that is derived from Shape, compiler will actually help as giving an error.

十二 2024-12-26 11:39:52

简单地说,将一个类声明为“抽象”类,就是为继承它的子类强制执行“契约”,因此它提供了维护“契约”的好方法。

Simply speaking, declaring a class to be "abstract", you are enforcing a "contract" for the child classes which inherit it, so it provides a good way to maintain the "contract".

谁许谁一生繁华 2024-12-26 11:39:52

如果抽象所做的只是声明抽象方法,那么您是对的,这有点愚蠢,并且接口可能会更好。

但抽象类通常会实现一些(甚至可能是全部)方法,只留下少数方法是抽象的。例如,抽象表模型。这节省了重写大量代码。

相对于接口的另一个“优点”是抽象类可以声明供子类使用的字段。因此,如果您非常确定任何合理的实现都会有一个名为 uniqueID 的字符串,您可以在抽象类中声明它以及相关的 getter/setter,从而节省稍后的一些输入。

If all an abstract does is declare abstract methods, you are correct, it's a bit silly, and an interface would likely be superior.

But often an abstract class implements some (maybe even all) of the methods, leaving only a few as abstract. For example, AbstractTableModel. This saves rewriting a lot of code.

Another "advantage" over an interface is that an abstract class can declare fields for subclasses to use. So, if you are pretty sure that any reasonable implementation would have a String named uniqueID, you could declare it, plus relevant getters/setters, in the abstract class, saving some typing later.

挽你眉间 2024-12-26 11:39:52

抽象方法必须由任何非抽象的子类重写。

因此,例如,您定义一个抽象类 Log 并强制子类重写该方法:

public abstract class Log{
  public void logError(String msg){
    this.log(msg,1)
  }
  public void logSuccess(String msg){
    this.log(msg,2)
  }
  public abstract void log(String msg,int level){}
}

public class ConsoleLog{
  public void log(String msg,int level){
    if(level=1){
       System.err.println(msg)
    }else{
       System.out.println(msg)
    }
  }
}

Abstract methods must be overriden by any subclass that will not be abstract.

So, for example you define an abstract class Log and you force the subclasses to override that method:

public abstract class Log{
  public void logError(String msg){
    this.log(msg,1)
  }
  public void logSuccess(String msg){
    this.log(msg,2)
  }
  public abstract void log(String msg,int level){}
}

public class ConsoleLog{
  public void log(String msg,int level){
    if(level=1){
       System.err.println(msg)
    }else{
       System.out.println(msg)
    }
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文