接口和类对象内存分配的区别

问题描述

假设有A接口和B类,B类实现了接口;

interface A {
  void hello();
}

class B implements A {
  public int justAField;

  @Override
  public void hello() {
    System.out.println("Hi.");
  }

  public void anotherMethod() {
    System.out.println("Another one.");
  }
}

假设我们有这两个对象;

A typeInterface = new B();
B typeClass = new B();

我的问题是,当编译器编译代码和内存分配开始时,我们有两个对象,对吗?但是一种是类型A,一种是类型B,这意味着'typeInterface'将只有一个方法,而'typeClass'将包含一个多字段和一个方法

这两个对象分配相同数量的内存还是'typeInterface'基本上消耗更少的内存?

解决方法

不,您有两个 B 类型的对象,一个存储在类型 A 的引用中,另一个存储在类型 B 的引用中。

两个对象共享相同的内存使用大小,但是您不能从类型 A 的引用(名为 typeInterface 的引用)访问 B 的方法,即使该方法存在于被引用的对象中,除非您强制转换它。如果您强制转换引用,则限制将被删除,您可以访问 anotherMethod

您必须区分引用和对象。这就是你所需要的。

,

我的问题是,当编译器编译代码和内存分配开始时,我们有两个对象对吗?

是的。

但是一种是类型A,一种是类型B,...

不!

两者都是 B 类型。表达式 new B(...) 创建一个 B。之后发生的事情不会改变这一点。

在第一个示例中,您将 B 实例的引用分配给类型为 A 的变量。这意味着当您通过该变量访问对象时,您将只能使用 A 功能(方法、字段)。

然而,对象本身仍然B 的一个实例,并且在对象的生命周期内将保持这种状态。我们可以证明1

  System.out.println(typeInterface.getClass().getName());

将打印“B”,而不是“A”。

我们可以更进一步,将 typeInterface 转换为 B 并使用 B 方法和字段...来表明它确实是一个 B .

它是一个 B。毫不含糊。

...这意味着“typeInterface”将只有一个方法,但“typeClass”将包含一个多字段和一个方法。

没有。不对。这个逻辑是基于一个错误的假设。见上文。

这两个对象分配相同数量的内存还是'typeInterface'基本上消耗更少的内存?

是的,它们使用相同数量的内存。它们都是 B 实例。见上文。


理解这一点的一种方法是,当您在此进行分配时:

A typeInterface = new B();

编译器“忘记”B(现在)所指对象的typeInterface-ness。它只“记住”它指的是 A 某种。然而,在运行时,运行时系统总是知道一个对象的真实类型是什么,这样它才能正确实现instanceof、类型转换、getClass()、方法分派等等


1 - Object::getClass() 的 javadoc 声明:“返回此 Object 的运行时类”

,

消耗内存的是对象实例。您的两个实例均由 new B() 创建,因此它们将占用相同数量的堆内存。

除了你的两个对象实例之外,你还有两个变量指向它们。这些存储在使用它们的方法的堆栈中。一个变量占用多少内存取决于它是原始变量还是对象引用,仅此而已。所有对象引用(无论其类型如何)在那里占用相同的空间。

,

接口只是确保对象在编译时在技术上和逻辑上都满足特定标准。当执行代码并使用接口时,内存将被分配,就像您只是使用类实例化对象一样。

因此以下之间没有区别(在内存分配方面):

A typeInterface = new B();

B typeClass = new B();

首先是新的 B() 语句,它在堆上分配 sizeof(B)。
二、堆分配地址的赋值存放在变量test中,在栈上分配为sizeof(object *)(即IntPtr.Size,或32/64位基于硬件+OS+软件运行) ).

以下语句在“分配”中完全相同:

 B typeClass = new B();

两者之间的唯一区别是可在变量“typeInterface”上调用的方法。

,

类:

类是用户定义的蓝图或原型,从中创建对象。它表示一种类型的所有对象共有的一组属性或方法。通常,类声明可以按顺序包含这些组件:

Modifiers: A class can be public or has default access (Refer to this for details).
Class name: The name should begin with an initial letter (capitalized by convention).
Superclass(if any): The name of the class’s parent (superclass),if any,preceded by the keyword extends. A class can only extend (subclass) one parent.
Interfaces(if any): A comma-separated list of interfaces implemented by the class,preceded by the keyword implements. A class can implement more than one interface.
Body: The class body surrounded by braces,{ }.

构造函数用于初始化新对象。字段是提供类及其对象状态的变量,方法用于实现类及其对象的行为。


界面: 和类一样,接口可以有方法和变量,但接口中声明的方法默认是抽象的(只有方法签名,没有人)。

Interfaces specify what a class must do and not how. It is the blueprint of the class.
An Interface is about capabilities like a Player may be an interface and any class implementing Player must be able to (or must implement) move(). So it specifies a set of methods that the class has to implement.
If a class implements an interface and does not provide method bodies for all functions specified in the interface,then the class must be declared abstract.
A Java library example is Comparator Interface. If a class implements this interface,then it can be used to sort a collection.