I have written the following Java source file (Hello.java
):
package com;
public class Hello {
public static void main(String[] args) {
System.out.println("Hello!");
}
}
I save this to C:/tmpjava/Hello.java
.
From the command line, I navigate to that directory and run javac Hello.java
. Then I run dir
:
Hello.class
Hello.java
Then, from the same directory that I just ran javac
from, I run java Hello.class
and get:
Exception in thread "main" java.lang.NoClassDefFoundError: Hello/class
Caused by: java.lang.ClassNotFoundException: Hello.class
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Could not find the main class: Hello.class. Program will exit.
What's going on here?!? How can javac
run fine, but not java
?
Your class Hello
belongs to the package com
. So the fully qualified name of your class is com.Hello
. When you invoke a program using java on the command-line, you should supply the fully-qualified class name of the class that contains your main
method and omit the .class, like so:
java com.Hello
The java program needs this fully-qualified class name to understand which class you are referring to.
But you have another problem. The java program locates packages, sub-packages, and the classes that belong to them using the filesystem. So if you have a package structure like com.Hello
, the java program expects to find a class file named Hello.class in a directory named com, like this: com/Hello.class. In fact you can observe this behavior in the Exception
that you see; you've incorrectly used Hello.class, which java is interpreting as a package named Hello
, and a class named class
, and is looking for the directory structure Hello/class:
java.lang.NoClassDefFoundError: Hello/class
But the compiler javac doesn't set up this directory structure by default. See the documentation for javac, but the important bit is this: when you do your compiles, you can specify a destination directory using the -d
flag:
-d directory
Set the destination directory for class files. The destination directory must already exist; javac will not create the destination directory. If a class is part of a package, javac puts the class file in a subdirectory reflecting the package name, creating directories as needed. For example, if you specify -d c:\myclasses and the class is called com.mypackage.MyClass, then the class file is called c:\myclasses\com\mypackage\MyClass.class.
If -d is not specified, javac puts the class file in the same directory as the source file.
The last bit in bold is the source of much confusion for beginners, and is part of your own problem.
So you have two alternatives:
In your case, it's fine if you supply the current directory as the destination directory, like so (the period .
means current directory):
javac -d . Hello.java
If you invoke the compiler like this, it will create the com directory for you, and put your compiled class file in it, the way that the java program expects to find it. Then when you run java as above, from c:\tmpJava, your program should execute.
You could set up your source code using a directory structure that mirrors your package structure: put your source file Hello.java inside a directory called com, in your case: c:\tmpJava\com\Hello.java. Now, from c:\tmpJava you can run your javac compile like this:
javac com\Hello.java
You haven't supplied the -d
flag, but that's fine, because you've created the directory structure yourself, and quoting again from the documentation above:
If -d is not specified, javac puts the class file in the same directory as the source file.
Again, when you run java as above, your program should execute.
Note that this second alternative is one that is commonly employed by java programmers: the source code files are organized in a directory structure that mirrors the package structure.
In this explanation we've ignored the concept of the classpath. You'll also need to understand that to write java programs, but in your case of simply compiling a program in the current directory - if you follow one of the two alternatives above when compiling your class - you can get away without setting a classpath because, by default, the java program has the current directory as a classpath. Another quote, this one from the documentation for java:
-cp classpath
Specify a list of directories, JAR archives, and ZIP archives to search for class files. Class path entries are separated by semicolons (;). Specifying -classpath or -cp overrides any setting of the CLASSPATH environment variable.
If -classpath and -cp are not used and CLASSPATH is not set, the user class path consists of the current directory (.).
Note that when you use an IDE like Eclipse to run your java code, this is mostly handled for you, but you'll still run into classpath issues.