[英]What is the point of using abstract methods?
使用“抽象方法”有什么意义? 抽象类无法实例化,但抽象方法呢? 他们只是在这里说“你必须实现我”,如果我们忘记它们,编译器会抛出错误吗?
这是否意味着别的什么? 我还读到了一些关于“我们不必重写相同代码”的内容,但在抽象类中,我们只“声明”抽象方法,因此我们必须重写子类中的代码。
你能帮我理解一下吗? 我检查了关于“抽象类/方法”的其他主题,但我没有找到答案。
假设您有三台打印机需要为Lexmark
, Canon
和HP
编写驱动程序。
所有三台打印机都将具有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();
}
除此之外,你必须实现它的提醒,最大的优点是任何人谁通过它的抽象类类型引用的对象(包括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
模式的接口,并将该接口的实例传递给不再抽象的基类。 在术语方面,那是使用组合而不是继承(你已经用两个对象,一个聚合器和一个加法器组成了一个加法聚合器)。
抽象方法仅定义派生类必须实现的契约。 这是你如何确保他们实际上永远都会这样做的方式。
所以我们以一个抽象类Shape
为例。 它将有一个抽象方法draw()
,它应该绘制它。 ( Shape
是抽象的,因为我们不知道如何绘制一般形状)通过在Shape
draw
抽象方法我们保证所有派生的类,实际上可以绘制,例如Circle
实现draw
。 稍后如果我们忘记在某个类中实现draw
,这是从Shape
派生的,编译器实际上会帮助提供错误。
简单地说,声明一个类是“抽象”的,你正在为继承它的子类强制执行“契约”,因此它提供了维护“契约”的好方法。
抽象类是包含一个或多个抽象方法的类。 抽象方法是声明的方法,但不包含任何实现。 抽象类可能无法实例化,并且需要子类来提供抽象方法的实现。 让我们看一个抽象类和抽象方法的例子。
假设我们通过创建一个以名为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 and Cow子类。
现在您可能想知道为什么不将抽象类声明为接口,并让Dog和Cow实现接口。 当然可以 - 但你也需要实施吃饭和睡眠方法。 通过使用抽象类,您可以继承其他(非抽象)方法的实现。 你不能用接口做到这一点 - 接口不能提供任何方法实现。
简单来说,接口应该包含所有抽象方法但不包含方法的实现,或者我们不能在接口中定义非抽象方法,在接口中所有方法都应该是抽象的,但在抽象类中我们可以定义抽象方法和非抽象方法,所以为了定义非抽象方法,我们不必定义另一个类来实现同一对象的行为,这是抽象类相对于接口的优点。
如果所有抽象都是声明抽象方法,那么你是正确的,它有点愚蠢,并且接口可能会更优越。
但是通常一个抽象类实现了一些(甚至可能是全部)方法,只留下一些抽象类。 例如,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)
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.