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

vcirk6k6  于 12个月前  发布在  其他
关注(0)|答案(4)|浏览(219)

我只是好奇他们是否被区别对待。
例如,如果我们有:
接口:

public interface Test {
    public void method();
}

抽象类:

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

JVM是否会对这些类进行不同的处理?两者中,哪一个在存储时占用的磁盘空间更多,哪一个将使用最多运行时内存哪一个操作更多(性能更好)。
这个问题不是关于何时使用接口或抽象类。

mo49yndu

mo49yndu1#

是的,他们是不同的。
有了接口,客户端可以实现它,也可以扩展一个类:

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

}

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

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

}

interfaceabstract class只有一个抽象方法声明时,会出现另一个差异,它与匿名函数(lambda)有关。
正如@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的语义强制执行的。
至于资源使用的差异,这不是什么值得担心的事情 *,除非它导致您的软件问题 *。**使用内存管理语言的想法是不要担心这些事情,除非你有问题。**不要预先优化,我相信差异是可以忽略的。即使存在差异,也应该只在可能导致软件问题时才有关系。
如果您的软件有资源问题,请分析您的应用程序。如果它确实导致了内存问题,您将能够看到它,以及每个问题消耗了多少资源。在那之前,你不用担心。您应该更喜欢使代码更易于管理的功能,而不是消耗最少资源的功能。

zzzyeukh

zzzyeukh2#

JVM内部结构和内存表示对于JVM来说几乎相同。我的陈述基于第四章-类文件格式。从所附文档中可以看出,JVM通过access_flags在类和接口之间产生差异。如果你有一个Simple接口只有一个方法和一个简单的抽象类只有一个方法。此格式中的大多数字段都是相同的(空),主要区别在于access_flags。
默认构造函数生成抽象类正如@Holger所指出的,Interface和Abstract类之间的另一个小区别是普通类需要构造函数。Java编译器将为Abstract类生成一个默认构造函数,该构造函数将被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接口

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

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

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

这一点在抽象类中是无法实现的。

**接口-缺乏“扩展的开放性”。**直到Java 8的接口都因缺乏可扩展性而受到批评。如果你改变了接口约定,你需要重构一个接口的所有客户端。

我想到的一个例子是Java MapReduce API for Hadoop,它在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

igsr9ssn

igsr9ssn3#

它们在实现上是不同的

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

1zmg4dgp4#

如果你在谈论性能,那么不久前有一种观点认为接口比抽象类慢。但是现在JIT在它们之间没有区别。
请参阅this answer了解更多详情。

相关问题