我只是好奇他们是否有任何不同的待遇。
例如,如果我们有:
界面:
public interface Test {
public void method();
}
抽象类:
public abstract class Test {
public abstract void method();
}
JVM 会不同地对待这些类?在存储期间,哪两个会占用更多的磁盘空间,哪一个占用最多的运行时内存哪一个会执行更多操作(执行得更好 )。
此问题与何时使用接口或抽象类无关。
答案 0 :(得分:6)
是的,他们是不同的。
通过接口,客户端可以实现它以及扩展类:
class ClientType implements YourInterface, SomeOtherInterface { //can still extend other types
}
使用类,客户端将能够扩展它,但不扩展任何其他类型:
class ClientType extends YourClass { //can no longer extend other types
}
当interface
或abstract 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的语义强制执行的。
至于资源使用的差异,除非它导致您的软件问题,否则不要担心 。 使用内存管理语言的想法是不要担心这些事情,除非你遇到问题。不要预先优化,我确定差异可以忽略不计。即使存在差异,只要它可能会导致您的软件出现问题。
如果您的软件遇到资源问题,请查看您的应用程序。如果它确实导致内存问题,您将能够看到它,以及每个消耗的资源量。在那之前,你不应该担心它。您应该更喜欢使代码更易于管理的功能,而不是消耗最少量的资源。
答案 1 :(得分:6)
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抽象类只有一个方法不是功能接口。
@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发布中更改为支持抽象类 接口,因为它们更容易发展。这意味着,一种新方法 可以添加到抽象类(使用默认实现),out 打破了类的旧实现。
引入 Java 8接口默认方法 这种缺乏可扩展性已得到解决。
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
答案 2 :(得分:0)
如果你谈论性能,那么前一段时间有人认为接口比抽象类慢。但是现在JIT没有区别。
请参阅this answer了解详情。
答案 3 :(得分:0)
它们在实施上有所不同