繁体   English   中英

普通接口类和只有抽象方法的抽象类之间有什么区别吗?

[英]Are there any differences between a normal interface class and an abstract class that only has abstract methods?

我只是好奇他们是否受到任何不同的对待。

例如,如果我们有:

界面:

public interface Test {
    public void method();
}

和抽象类:

public abstract class Test {
    public abstract void method();
}

JVM会以不同的方式对待这些类吗? 两者中哪一个在存储过程中占用更多的磁盘空间,哪一个会占用最多的运行时内存,哪个执行更多的操作(性能更好)。

这个问题与何时使用接口或抽象类无关。

是的,它们是不同的。

使用接口,客户端可以实现它以及扩展一个类:

class ClientType implements YourInterface, SomeOtherInterface { //can still extend other types

}

使用类,客户端将能够扩展它,但不能扩展任何其他类型:

class ClientType extends YourClass { //can no longer extend other types

}

interfaceabstract class只有一个抽象方法声明时,就会出现另一个区别,它与匿名函数(lambdas)有关。

正如@AlexanderPetrov 所说,具有一种方法的接口可以用作功能接口,允许我们在指定功能接口类型的地方“即时”创建函数:

//the interface
interface Runnable {
    void run()
}

//where it's specified
void execute(Runnable runnable) {
    runnable.run();
}

//specifying argument using lambda
execute(() -> /* code here */);

这不能用abstract class来完成。 所以你不能互换使用它们。 区别在于客户端如何使用它的限制,这是由 JVM 的语义强制执行的。

至于资源使用的差异,除非它导致您的软件问题,否则无需担心。 使用内存管理语言的想法是不要担心这些事情,除非您遇到问题。 不要预先优化,我确定差异可以忽略不计。 即使存在差异,也只有它是否可能导致您的软件出现问题才重要。

如果您的软件存在资源问题,请分析您的应用程序。 如果它确实导致内存问题,您将能够看到它,以及每个人消耗了多少资源。 在此之前,您不必担心。 您应该更喜欢使代码更易于管理的功能,而不是消耗最少资源的功能。

JVM 内部结构和内存表示 JVM几乎相同。 我的陈述基于第 4 章 - 类文件格式 从附带的文档中可以看出, JVM通过access_flags区分了类和接口。 如果你一个方法只有一个方法的简单抽象类的简单接口。 此格式中的大多数字段将相同(空),主要区别在于 access_flags。

默认构造函数生成抽象类正如@Holger 所指出的,Interface 和 Abstract 类之间的另一个小区别是普通类需要一个构造函数。 Java 编译器将为Abstract 类生成一个默认构造函数,该构造函数将为它的每个子类调用。 从这个意义上说,与接口相比,抽象类定义会稍微大一些。

https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html

ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

除了接口的多重继承,还有一个不同点就是Java8中只有一个方法的抽象类不是Functional interface

 @FunctionalInterface
 public interface SimpleFuncInterface {
      public void doWork();
 }

 execute(SimpleFuncInterface function) {
      function.doWork();
 }

 execute(()->System.out.printline("Did work"));

同样不能用抽象类来实现。

接口 - 缺乏“对扩展的开放性”。 高达 Java 8 的接口因其缺乏可扩展性而受到批评。 如果更改接口契约,则需要重构接口的所有客户端。

想到的一个例子是用于 Hadoop 的 Java MapReduce API,它在 0.20.0 版本中进行了更改,以支持抽象类而不是接口,因为它们更容易发展。 这意味着,可以将新方法添加到抽象类(具有默认实现),而不会破坏类的旧实现。

随着Java 8 Interface Default 方法的引入,这种缺乏可扩展性的问题已经得到解决。

public interface MyInterface {
 int method1();
 // default method, providing default implementation
 default String displayGreeting(){
  return "Hello from MyInterface";
 }
}

使用 Java 8 可以将新方法添加到接口和抽象类中,而不会破坏客户端类的约定。 http://netjs.blogspot.bg/2015/05/interface-default-methods-in-java-8.html

它们在实现上是不同的

  • 你只能扩展一个抽象类
  • 另一方面,您可以同时实现多个接口
  • 您需要实现接口中存在的所有方法
  • 对于抽象,它可能会提供一些默认实现,因此您是想再次实现它还是只使用默认实现是独立的

如果您谈论性能,那么前一段时间有人认为接口比抽象类慢。 但是现在 JIT 对它们没有任何区别。

请参阅此答案以获取更多详细信息。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM