繁体   English   中英

接口与Class object memory分配的区别

[英]Difference between Interface and Class object memory allocation

假设有接口A和class B,class 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();

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

这两个对象是否分配相同数量的 memory 或“typeInterface”基本上消耗更少的 memory?

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

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

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

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

是的。

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

不!!

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

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

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

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

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

我们可以通过将typeInterface强制转换为B并使用B方法和字段来进一步证明它是一个B

它是一个B 毫不含糊。

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

不,不正确。 这个逻辑是基于一个错误的假设。 看上面。

这两个对象是否分配相同数量的 memory 或“typeInterface”基本上消耗更少的 memory?

是的,他们使用相同数量的 memory。 它们都是B实例。 看上面。


理解这一点的一种方法是,当您执行以下任务时:

A typeInterface = new B();

编译器“忘记” typeInterface (现在)所指的 object 的B特性。 它只“记住”它指的是某种A 但是,在运行时,运行时系统总是知道对象的真实类型是什么,因此它可以正确地实现instanceof 、类型转换、 getClass() 、方法分派等。


1 - Object::getClass()的 javadoc 状态: “返回此 Object 的运行时Object

消耗 memory 的是 object 实例。 您的两个实例都是由new B()创建的,因此它们将占用相同数量的堆 memory。

除了您的两个 object 实例之外,您还有两个指向它们的变量。 这些存储在使用它们的方法的堆栈中。 一个变量需要多少 memory 取决于它是原语还是 object 参考,但仅此而已。 所有 object 引用(不管它们的类型)在那里占用相同数量的空间。

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

所以没有区别(就 memory 分配而言):

A typeInterface = new B();

B typeClass = new B();

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

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

 B typeClass = new B();

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

Class:

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

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, if any, preceded by the keyword implements. A class can implement more than one interface.
Body: The class body surrounded by braces, { }.

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


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

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.

让我们成为界面

interface A {
    void hello();
    void hello2();
}

我们可以立即以接口为参数定义function

void function example (A i) {
    i.hello();
    i.hello2();
}

这里究竟会编译什么? 接口 function 调用。

这怎么可能? 这是可能的,因为接口类型变量包含的函数指针与接口中定义的函数一样多。 简而言之,接口是一个包含指向函数的指针变量的结构。

现在任何实现该接口的 class 都可以分配给它。 通过这种分配,指向(接口的)函数的指针变量被“填充”了位于(类的)vmtable 中的函数的地址。

这意味着接口变量总是能看到其中定义的函数,并且只能看到它们(除非强制转换为类)


例如,如果 class 实现了接口。

class B implements A {
  public int justAField;
  @Override
  public void hello() {
    System.out.println("Hi.");
  }
  @Override
  public void hello2() {
    System.out.println("Hi2.");
  }
  public void anotherMethod() {
    System.out.println("Another one.");
  }
}

我们可以有

example(new B());

调用i.hello(); i.hello2(); i.hello(); i.hello2(); 触发 class 的相应功能(通过 function 指针)

暂无
暂无

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

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