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.
Foo f = new Foo();still has its' type information. I think you're confused with generics.classfile.