Difference between Interface and Class object memory allocation

Viewed 530

Suppose there are Interface A and class B, and class B implements the interface;

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.");
  }
}

And let's say, we have these two objects;

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

My question is, when compiler compiles the code and when the memory allocation begins, we've got two objects right? But one is type A, one is type B, that means 'typeInterface' will have only one method, but 'typeClass' will contain one more field and one more method.

Does these two objects allocate the same amount of memory or 'typeInterface' basically consume much less memory?

6 Answers

No, you have two objects of type B, one stored on a reference of type A, the other one stored on a reference of type B.

Both objects share the same memory usage size, but you cannot access the methods of B from the reference of type A (the reference named typeInterface), even if the method exists at the referenced object, unless you cast it. If you cast the reference, then the restriction is removed and you can access anotherMethod.

You must differentiate between references and objects. That's all you need.

My question is, when compiler compiles the code and when the memory allocation begins, we've got two objects right?

Yes.

But one is type A, one is type B, ...

No!!

Both are type B. The expression new B(...) creates a B. What happens after that doesn't change that.

In the first example, you are then assigning the reference for a B instance to a variable whose type is A. That means that you will only be able to use A features (methods, fields) when you access the object via that variable.

However, the object itself is still an instance of B, and will remain that way for the lifetime of the object. And we can prove it1.

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

will print "B", not "A".

And we can go a step further by casting typeInterface to a B and using the B methods and fields ... to show that it is really a B.

It is a B. Unequivocally.

... that means 'typeInterface' will have only one method, but 'typeClass' will contain one more field and one more method.

No. Not true. This logic is based on a false assumption. See above.

Does these two objects allocate the same amount of memory or 'typeInterface' basically consume much less memory?

Yes they user the same amount of memory. They are both B instances. See above.


One way to understand this is that when you do the assignment in this:

A typeInterface = new B();

the compiler "forgets" about the B-ness of the object that typeInterface (now) refers to. It only "remembers" that it refers to an A of some kind. However, at runtime, the runtime system always knows what an object's real type is, so that it can correctly implement instanceof, type-casts, getClass(), method dispatching and so on.


1 - The javadoc for Object::getClass() states: "Returns the runtime class of this Object".

What consumes memory are object instances. Both of your instances are created by new B() so they will take up the same amount of heap memory.

In addition to your two object instances, you also have two variables pointing to them. These are stored on the stack of the method that uses them. How much memory a variable takes depends on it being a primitive or an object reference, but that's it. All object references (regardless of their type) take up the same amount of space there.

Interface simply makes sure that objects meet a certain criteria both technically and logically at compile time. When executing the code and using an interface, memory will be allocated as if you would just instantiate the object using the class.

So there's no difference (in terms of memory allocation) between:

A typeInterface = new B();

and

B typeClass = new B();

First is the new B() statement which allocates sizeof(B) on the heap.
Second, the assignment of the address of the heap allocation is stored in the variable test, which is allocated on the stack as sizeof(object *) (i.e. IntPtr.Size, or 32/64 bits based on the hardware+OS+software running).

The following statement is EXACTLY the same in 'allocations':

 B typeClass = new B();

The only difference between the two is the methods available to be called on the variable 'typeInterface'.

Class:

A class is a user-defined blueprint or prototype from which objects are created. It represents the set of properties or methods that are common to all objects of one type. In general, class declarations can include these components, in order:

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, { }.

Constructors are used for initializing new objects. Fields are variables that provide the state of the class and its objects, and methods are used to implement the behavior of the class and its objects.


Interface: Like a class, an interface can have methods and variables, but the methods declared in the interface are by default abstract (only method signature, nobody).

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.

Let be the interface

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

We can immediately define the function with the interface as a parameter

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

What exactly will be compiled here? Interface function calls.

And how is this possible? It is possible because an interface type variable contains as many pointers to functions as there are functions defined within the interface. Interface in short is a structure that contains pointer variables to functions.

Now any class that implements the interface can be assigned to it. With this allocation, pointer variables to functions (of the interface) are "filled" with the addresses of the functions located in the vmtable (of the class).

This means that an interface variable always sees the functions defined in it and only them (unless casted to the class)


So for example if a class implements the interface.

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.");
  }
}

We can have

example(new B());

The calls i.hello(); i.hello2(); trigger the corresponding functions of the class (via function pointers)

Related