1

From what I read before, after .java file compiles to .class files, every object is simply Object after erasure. Such as

Foo f = new Foo();

Compiles to .class file, and decompile, it becomes:

Object f = new Foo();

So how does JRE call the function of an object when running? Where is the function stored in the memory? Inside the object? Or with a hierarchy of class structure and does lookup up the hierarchy?

11
  • 2
    but every object is simply Object. No...where did you read that? Commented Jan 14, 2014 at 18:34
  • @SotiriosDelimanolis Confusion with type erasure? Commented Jan 14, 2014 at 18:35
  • 3
    No... Foo f = new Foo(); still has its' type information. I think you're confused with generics. Commented Jan 14, 2014 at 18:36
  • @ElliottFrisch maybe I need to rephrase it. I know every object still typed, but my question how does it do function lookup and where is the function stored? Commented Jan 14, 2014 at 18:37
  • 1
    In the class when the class was compiled (and then in the Object when the Object was instantiated)... try using javap on your class file. Commented Jan 14, 2014 at 18:39

5 Answers 5

4

According to the Java spec and wikipedia

There are 10 basic sections to the Java Class File structure:

  • Magic Number: 0xCAFEBABE
  • Version of Class File Format: the minor and major versions of the class file
  • Constant Pool: Pool of constants for the class
  • Access Flags: for example whether the class is abstract, static, etc.
  • This Class: The name of the current class
  • Super Class: The name of the super class
  • Interfaces: Any interfaces in the class
  • Fields: Any fields in the class
  • Methods: Any methods in the class
  • Attributes: Any attributes of the class (for example the name of the sourcefile, etc.)

At run time, the type of the object is retrieved, its class file (or rather the virtual method table) is checked for an implementation of the method invoked. If that class doesn't have such an implementation, the parent class is checked (retrieved from super class entry), and so on, eventually failing if none is found.

Sign up to request clarification or add additional context in comments.

2 Comments

So you mean the classes were not preloaded? Rather it checks the file on the disk every time?
@texasbruce The .class files contain the byte code for the methods. I believe it's up to the JVM to cache them or look them up every time. Depends on implementation (but let's be real).
1

When you declare

Foo f;

at any point during f's lifetime, it can be a reference to objects that aren't of type Foo. The object type can be Foo or any of its subclasses. Therefore, the object must store information about the actual ("runtime") type of the object, somewhere within each object. (I believe this information is associated with the object itself, not with references to the object such as f.) I don't know exactly what the format of this information looks like in JVM. But in other compiled languages I've worked with, the type information includes a pointer to a vector of code addresses. If the type Foo declares methods method1(), method2(), etc., then each one will be given an index number (and that number will be preserved for methods that are inherited or overridden in subclasses). So calling a method means going to that vector and finding the function address for the given index. This will work whether the actual run-time type is Foo or any subclass of Foo.

Comments

1

Example code:

import java.util.*;

public class Foo {
    public static void main() {
        Foo foo = new Foo();
        Object obj = new Object();
        foo.f();

        ArrayList<Foo> fooList = new ArrayList<Foo>();
        ArrayList objList = new ArrayList();
    }

    public void f() {
    }
}

Generated JVM instructions (javap -c Foo):

public class Foo {
  public Foo();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public static void main();
    Code:
       0: new           #2                  // class Foo
       3: dup           
       4: invokespecial #3                  // Method "<init>":()V
       7: astore_0      
       8: new           #4                  // class java/lang/Object
      11: dup           
      12: invokespecial #1                  // Method java/lang/Object."<init>":()V
      15: astore_1      
      16: aload_0       
      17: invokevirtual #5                  // Method f:()V
      20: new           #6                  // class java/util/ArrayList
      23: dup           
      24: invokespecial #7                  // Method java/util/ArrayList."<init>":()V
      27: astore_2      
      28: new           #6                  // class java/util/ArrayList
      31: dup           
      32: invokespecial #7                  // Method java/util/ArrayList."<init>":()V
      35: astore_3      
      36: return        

  public void f();
    Code:
       0: return        
}

As you can see, Foo foo = new Foo(); gets translated to:

0: new           #2                  // class Foo
3: dup           
4: invokespecial #3                  // Method "<init>":()V
7: astore_0

while Object obj = new Object(); turns into:

8: new           #4                  // class java/lang/Object
11: dup           
12: invokespecial #1                  // Method java/lang/Object."<init>":()V
15: astore_1 

new allocates memory for the object and stores a reference in the stack, dup creates a second reference in the stack, invokespecial calls the constructor (which is actually a method called <init>). Then, the instance is stored in a local variable with astore_1.

As for ArrayList<Foo> fooList = new ArrayList<Foo>(); and ArrayList objList = new ArrayList();, they compile to nearly the same thing:

28: new           #6                  // class java/util/ArrayList
31: dup           
32: invokespecial #7                  // Method java/util/ArrayList."<init>":()V
35: astore_3

One uses astore_2 and the other one uses astore_3. That's because they are stored in different local variables. Other than that, the generated code is the same, which means that the JVM can't tell Arraylist<Foo> from Arraylist, which is what they call type erasure. However, it can very easily tell Foo from Object.

1 Comment

I love the smell of bytecode in the morning. Not enough answers take the time to delve into the low level! :)
0

Your example is a local variable. Local variables exist only within a function, and are not accessible to the outside world. As a result, there is no need for the compiler to store information about the variable in the classfile (this is not type erasure, which refers to losing information about parameterized types).

In the classfile, local variables are referenced as numbered slots within the stack frame. Thus, the bytecode operator aload_0 retrieves the value in slot 0 (which will be this for instance methods) and puts it on the top of the operand stack, while astore_1 takes the reference off the top of the operand stack and puts it in slot 1 of the frame.

Since the compiler knows the type of each slot in the frame, it can ensure that only the correct methods get called. The JVM provides an extra check: if you could modify the slot to contain an invalid object reference, the invokevirtual operation would fail.

While there's no need to store type information about local variables to run your program, there is a need to have that information for debugging. So you can give the compiler the -g switch, which causes it to put a LocalVariableTable in your classfile. This table contains the original name and type of each local variable.

If your decompiler is showing local variables as Object, it means one of two things: (1) the classfile was written without debugging information, or (2) the decompiler isn't smart enough to apply that information to the bytecode.

Comments

-1

if you take a look at the VM specification you will see that the code of each method for each class is stored in the class .class file. see this link class file format

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.