Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/375.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如果我们可以使用空的具体方法,为什么还要强迫自己在具体的子类中实现抽象方法呢?_Java_Abstract - Fatal编程技术网

Java 如果我们可以使用空的具体方法,为什么还要强迫自己在具体的子类中实现抽象方法呢?

Java 如果我们可以使用空的具体方法,为什么还要强迫自己在具体的子类中实现抽象方法呢?,java,abstract,Java,Abstract,在创建一个抽象超类之后,当您到达第一个具体的子类时,您必须实现所有的抽象方法,即使其中的一些方法不会在该具体类中使用。所以为什么抽象超类不把这些抽象方法变成“假”方法,比如: public void doThis() { if (1 < 0){ int x = 34 } } 这两种方法都允许多态性,对吗?那么,我所缺少的抽象方法的真正优势是什么呢 谢谢 这取决于你为什么首先需要一个抽象方法。例如,模板方法设计模式要求抽象方法返回一个值。显然,编

在创建一个抽象超类之后,当您到达第一个具体的子类时,您必须实现所有的抽象方法,即使其中的一些方法不会在该具体类中使用。所以为什么抽象超类不把这些抽象方法变成“假”方法,比如:

public void doThis() { 
     if (1 < 0){ 
          int x = 34
     }
}
这两种方法都允许多态性,对吗?那么,我所缺少的抽象方法的真正优势是什么呢


谢谢

这取决于你为什么首先需要一个抽象方法。例如,模板方法设计模式要求抽象方法返回一个值。显然,编译器无法猜测您想要返回什么值。

如果您没有实现所有抽象基类的方法,那么您的设计就有问题。

这个想法是为了强制执行一个策略,即当您使用抽象类时:

a) 抽象类无法实例化

b) 你必须“填空”抽象的东西是如何完成的——换句话说,你需要把抽象的东西具体化

我们不需要这些东西,但它使设计意图清晰明了。它减少了错误。如果我们遵循您的方法,就不会进行编译时检查以确保遵循“规则”


请注意,许多语言,如javascript,都没有“抽象”的概念,人们仍然使用javascript编写优秀的软件。

抽象方法可以防止部分实现子类的错误。如果基本方法是具体的和空白的,编译器将允许您重新实现一些虚拟方法,而不是其他方法


在某些情况下,这是理想的结果。但通常不是这样。

有几件事你没有考虑。有抽象类和抽象方法。抽象类不能直接实例化,也就是说,它们只是模板。抽象方法只能在abstrac类中定义,必须为空(即没有主体),但我们都知道这一切。但是,抽象类可以提供非抽象方法。一个完美的例子是Log4j的AppenderSkeleton(参见)

AppenderSkeleton
是一个抽象类。它有可以重写的具体方法,它有一个抽象方法(
append
),如果要继承,则必须实现它(除非您的类也是一个抽象类),还有两个来自
Appender
接口的方法,也需要实现或作为抽象传递给任何子类(
close
requireLayout

现在,如果您想编写自己的appender,比如说,在tweet上发布一些东西,您可以从以下开始:

public class TweetAppender extends AppenderSkeleton {

    public boolean requiresLayout() {
        return false;
    }

    public void close() {
        // do nothing        
    }

    @Override
    protected void append(LoggingEvent event) {
        // take the message and tweet it!
    }    
}
因此,所有关于日志记录的复杂问题(使用过滤器、设置级别、错误处理程序)远离您。您只需执行实际的日志记录,log4j将为您完成其余的工作。当然,如果您愿意,您的
TweetAppender
可以覆盖其他方法。也许您需要执行特殊的错误处理,在这种情况下,您只需要覆盖
setErrorHandler

现在,假设您还想为Facebook实现一个appender,另一个用于更改您在Skype上的状态。假设它们都通过Web服务公开API,以便发布状态更新、更改等。很快,您就会意识到有两件事情是类似的,比如调用Web服务等等。此外,你注意到Skype有一些格式,而Tweeer有另一种格式,还有其他格式。所以你明智地设计了一个WebServiceAppender:

public abstract class WebServiceAppender extends AppenderSkeleton {
    public boolean requiresLayout() {
        return false;
    }

    public final void close() {
        // do extra clean up of resources
    }

    // make this final so no one can do strange stuff
    protected final void append(LoggingEvent event) {
        // do a lot of stuff, like, opening up a connection
        // send an xml, close the connection and stuff...
        // ...
        // ready to send the message!
        final String messageToSend = getFormattedMessage(event);
        // send the message and do lots of complicated stuff
        // ...
        // close and clean up
    }

    // let the implementations decide on the format
    protected abstract String getFormattedMessage(LoggingEvent event); 
}
现在,您的
tweetpender
看起来像

public class TweetAppender extends WebServiceAppender {
    @Override
    protected String getFormattedMessage(LoggingEvent event) {
        // use tweeter's specific format
    }

    public boolean requiresLayout() {
        return super.requiresLayout();
    }
}
通过将
getFormattedMessage
声明为抽象,
WebServiceAppender
强制任何实现实际提供一个执行
LoggingEvent
并返回
字符串的实现。另外,请注意,通过将
append
close
方法声明为final,
WebServicecAppender
禁止任何重写这些方法的实现。
requireLayout
方法仍然可以被重写

继承抽象类的类的另一个很酷的特性是使用
super
。将其视为父类“
this
。对于TweetAppender,requiresLayout方法的实现决定了基本上推迟了通过简单使用t他是家长班的学生

因此,把所有这些放在一起:

public class YourParentClass {
    public void doThis() { 
       if (1 < 0){ 
           int x = 34
    } 
}

public class YourChildClass extends YourParentClass {
    @Override
    public void doThis() {
        // do I want to do this, or something else?
        if (iGuessIWillDoThis) {
            super.doThis();
        } else {
            // do something else
        }
    }
}
公共类YourParentClass{
public void doThis(){
如果(1<0){
int x=34
} 
}
公共类YourChildClass扩展了YourParentClass{
@凌驾
公开无效{
//我想做这个还是别的什么?
如果(我会做这件事){
太好了;
}否则{
//做点别的
}
}
}

>我的两分钱。

BTW,你是在谈论C++还是java?就我而言,java在界面中几乎总是比抽象基类更好的设计。@福尔马里,我不同意,它们完全不同。注意你可以将它们一起使用。接口是用来定义行为的,抽象类是为了提供一些功能。但允许以后填写最终细节。并非所有抽象类的方法都被设计为重写。
public class YourParentClass {
    public void doThis() { 
       if (1 < 0){ 
           int x = 34
    } 
}

public class YourChildClass extends YourParentClass {
    @Override
    public void doThis() {
        // do I want to do this, or something else?
        if (iGuessIWillDoThis) {
            super.doThis();
        } else {
            // do something else
        }
    }
}