A coworker (who is very new to Java) stopped in today and asked what seemed like a very simple question. Unfortunately, I did an absolutely horrible job of trying to explain
A Class is just a blue print that describes what each and every instance of the class will look like and behave like. Depending on the visibility of the class and its constructors, code in the same class, in the same package, or complete strangers may create instances.
It is for example common to provide a factory method in classes where the constructor should not be public:
public class Foo {
// only I get to create new instances
private Foo() {
}
// but you can get instances through this factory method
public static Foo createFoo() {
return new Foo();
}
}
It's not a forward reference in the C/C++ sense. Your main method is referring to the class as a type inside its own context. You aren't "ahead" of anything.
The fact that main is static isn't germane, because it'll still work even for non-static methods:
public class Foo
{
private String x;
public Foo(String x) { this.x = x; }
public Foo(Foo f) { this.x = f.x; } // copy constructor; still compiles fine, even without static
}
One difference is the compilation and linking. C/C++ have separate compilation and linking steps. Java has a class loader. I think compiling to byte code and loading as needed at runtime using the class loader is a subtle difference between Java and C/C++ that explains why the forward reference idea isn't needed, but I'm not certain.
If your coworker is coming from a C or pascal programming background this question is abolutely logical. In a C program methods have to be declared above the line where they are first used. As its not always practical to order functions in this order, there are forward declarations that just give the methods name, return type and parameters, without defining the function body:
// forward declaration
void doSomething(void);
void doSomethingElse(void) {
doSomething();
}
// function definition
void doSomething(void) {
...
}
This was done to simplify the creation of a parser and to allow faster parsing since fewer passes over the source are needed. In Java however, identifiers are allowed to be used before their point of definition. Therefor parsing has to happen in several phases. After a syntax tree corresponding to the source code is build, this tree is traversed to determine all definitions of classes or methods. The method bodies are processed at a later stage, when all information about the names in scope are known.
So by the point that the method body of your main method is processed the compiler knows of the default constructor of your class and its doIt method and can generate the correct bytecode to call exactly this method.
Because the main method is static. And by static, it means that the method doesn't belong to any particular instance of the class. That is, it can be accessed without creating an instance.
Thus, in order to invoke the doIt
method which is non-static, one must create an instance of the class which holds it.
Because code is compiled first, and executed later. All the compiler needs to know to validate that line is that a class named XCopy exists, and that it has a no-argument constructor. It doesn't need to know everything about the class.
The jvm loads the class whenever it is first "mentioned". Then there is nothing to prevent instantiation - it is already loaded