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

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

这是否意味着别的什么? 我还读到了一些关于“我们不必重写相同代码”的内容,但在抽象类中,我们只“声明”抽象方法,因此我们必须重写子类中的代码。

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

除了提示你必须实现它之外,最大的好处是任何通过其抽象类类型引用该对象的人(包括抽象类本身中的这个)都可以使用该方法。

例如,假设我们有一个类负责处理状态并以某种方式操纵它。 抽象类将负责获取输入,将其转换为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模式的接口,并将该接口的实例传递给不再抽象的基类。 在术语方面,那是使用组合而不是inheritance(你已经用两个对象,一个聚合器和一个加法器组成了一个加法聚合器)。

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

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

但是,每台打印机只有print()不同。 getSystemResource()在三台打印机中保持不变。 您还有另一个问题,您想应用多态。

因为getSystemResource()对于所有三个打印机都是相同的,所以这可以推送到超类来实现,在Java中,这可以通过在超类中进行抽象来实现,并且可以在一个超类,类本身也需要是抽象的。

 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(); } 

抽象方法仅定义派生类必须实现的契约。 这是你如何确保他们实际上永远都会这样做的方式。

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

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

如果所有抽象都是声明抽象方法,那么你是正确的,它有点傻,界面可能会更优越。

但是,通常一个抽象类实现了一些(甚至可能是全部)方法,只留下一些抽象类。 例如,AbstractTableModel。 这样可以节省大量代码的重写。

接口的另一个“优点”是抽象类可以声明要使用的子类的字段。 因此,如果您非常确定任何合理的实现都会有一个名为uniqueID的String,您可以在抽象类中声明它以及相关的getter / setter,以后再保存一些输入。

抽象方法必须被任何不抽象的子类覆盖。

因此,例如,您定义了一个抽象类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) } } }