Sun’s free Java compiler that comes bundled with the JDK.
If you install Java 1.6.0_17
in the default directory you should find it in J:\Program Files\java\jdk1.6.0_17\bin\javac.exe.
Class and File Naming Rules
A class name must start with a capital letter. The source for that class must
live in a plain text file with the same name (including case), with a *.java
extension.
You cannot put more than one public class inside a *.java
file.
Classes in the same package are accessible to each other, even if they are in
different files. To access other classes, you must import them.
The source code must be stored in a directory with the same name as the package
declared at the top of the file, including case, with the dots replaced by \ or
/ or whatever your platform uses for directory element separators.
Package names must be lower case, usually beginning com.yourwebsite
to ensure global uniqueness.
It is a good idea to put every class in some package. Only experiments you plan
to keep for under an hour should be without a package.
CLASSPATH And File Naming Recipes
Here are my simplified rules for using CLASSPATH and naming the files on the
javac.exe command line:
- Use JDK 1.1 or later, why not the latest? Configure
your SET CLASSPATH= to clear it out. Avoid JDK 1.0
if you can because its CLASSPATH is more complicated since you need to put the
standard class jars on the classpath.
- In all that follows, everything is strictly case sensitive.
- To compile a HelloWorld.java app in the default
package in C:\MyDir, use:
CD \MyDir
javac.exe -classpath . HelloWorld.java
- To compile a HelloWorld.java app in C:\com\mindprod\mypackage,
in package com.mindprod.mypackage, use
CD \
javac.exe -classpath . com\mindprod\mypackage\HelloWorld.java
The Javac.exe Command Line
- Unlike with java.exe, you must specify the extension (*.java).
- The switches are case sensitive.
| Javac.exe Command Line Switches |
| Option |
Effect |
| -g |
generate all debugging information |
| -g:none |
remove all debugging information |
| -o |
optimise |
| -Xdepend |
Use a much slower more conservative approach to deciding which files need to
be recompiled. |
| -nowarn |
suppress warning messages. |
| -verbose |
long version of error messages. |
| -classpath /mydir:/place/myCollection.jar |
overriding CLASSPATH environment variable, colon/semicolon separated.
Infuriatingly, javac.exe won’t let you use the -cp shortcut. |
| -sourcepath /mydir:/place/myCollection.jar |
like CLASSPATH but describes with source *.java
files are rather than *.class files, colon/semicolon
separated. |
| -nowrite |
don’t actually generate code, just check the syntax. |
| -deprecation |
warn of any use of any deprecated methods. |
| -d targetDir |
Place the output class files in this directory rather than the usual same
directory as source. |
| -encoding UTF-8 |
what encoding was used to create the source files. Lets you embed fancy
characters you would otherwise need to encode with \uxxxx. |
| -J runtimeflag |
|
| @listOfFiles.txt |
To shorten or simplify the javac command, you may specify one or more files
that themselves contain one filename per line. This enables you to overcome the
command-line length limitation of Windows. |
| -source 1.3 |
What source code features you plan to use:
| Javac.exe Source and Target Options |
| Version |
Options |
Notes |
| 1.6 |
-source 1.6 -target 1.6
-Xlint:unchecked
-Xlint:fallthrough |
nothing new added. |
| 1.5 |
-source 1.5 -target 1.5
-Xlint:unchecked
-Xlint:fallthrough |
added generics, enumerations and annotations. |
| 1.4 |
-source 1.4 -target 1.4 |
added assertions and nio |
| 1.3 |
-source 1.3 -target 1.3 |
added Swing |
| 1.2 |
-source 1.3 -target 1.2 |
added ArrayList and other Collections. You must lie and code this as -source
1.3. |
| 1.1 |
-source 1.3 -target 1.1 |
added a totally new event model, using Listeners. This is the level
Microsoft has trapped many of its customers at. You must lie and code this as -source
1.3. |
If your code does not use generics, for example, but does use assertions, you
would set -source 1.4 to ensure you did not
inadvertently use any generics, destroying the 1.4 compatibility. If you wanted
to allow generics to be used, select -source 1.5. You
will discover by experiment that Javac does not support all logical combinations
of -source and -target. You
just have to humour it. |
| -target 1.1 |
Specifies which the lowest number of JRE you intend to run this code on. You
can also specify -target 1.2 and 1.3. It is not
smart enough to warn you if you use classes or methods not part of that class
library. You have to discover those errors by runtime tests. In Eclipse and
other advanced IDEs you can configure the JDK 1.5
compiler to use the JDK 1.4 library if you have
that JRE also installed, which will catch these errors. If you use -target
1.4 and the 1.5 compiler you can force the compiler to use the 1.4
classfiles on the command line with
-bootclasspath J:\j2sdk1.4.2_19\jre\lib\rt.jar
That way you can detect use of 1.5 classes that did not exist in 1.4, at compile
time, e.g. StringBuilder.
In JDK 1.3-, the colours had
lower case names such as Color. white.
Since these are static
final constants, in JDK 1.4+, Sun gave them
proper upper case names such as Color.WHITE.
However, beware of using the upper case names it you want to target JDK 1.3-
versions.
Your programs will explode in a glory of
exceptions from the missing support. The lower case names will work in any JDK
version.
|
| -version |
Verify you are using the version of javac.exe you
think you are using. |
| -Xstdout |
Send error messages to stdout instead of stderr. This makes them easier to
redirect to a file in Windows. For some idiotic reason this is no longer
supported under JDK 1.3, (a result of
intercorporate sniping at Microsoft?) It is supported with oldjavac.exe.
Use tcc/TakeCommand to independently redirect
stdout and stderr. |
| -help |
Get a list of options and what they do. Trust what it says over what I say
here. Knowledge keeps no better than fish. |
Note there is no -cp or -jar
option! Instead you must use -classpath for both
functions.
Programmatic Javac Invocation
In JDK 1.5- you have the deprecated, undocumented sun.tools.javac.Main
to fire up the Javac.exe compiler to run in the same
JVM and compile under your control. In JDK 1..6+
you have the official JavaCompiler interface. JavaCompiler
also allows you to compile on-the-fly generated code
that lines only in RAM, never on hard disk.
What Gets Recompiled?
Any time you change the value of a static final
constant, delete all the class files and recompile, aka clean compile. Otherwise
classes that reference those static finals might
not get recompiled, and they will be stuck on the old value.
Before you release code, or do a major test, do a clean compile.
javac.exe will recompile all the *.java
files you mention on the command line, whether they need it or not. Further, if
your java source references *.class files not mentioned
on the command line and they are missing, it will recompile them too. If the
referenced class files are out of date, javac will
recompile them, however, if other classes depend on the those freshly recompiled
classes, they will not get automatically recompiled. That is why you
should periodically delete all class and jar files in the universe and recompile
everything especially before any release or global testing. This is known as a clean
build. What I just said is not quite true. Javac.exe
will look for *.class files on the classpath and if it
can’t find them search the sourcepath (-sourcepath
option) for the matching *.java files to recompile. By
default, the sourcepath is the same as the classpath.
In ant, by default, the sourcepath is null in order to suppress recompiling
classes outside the package being compiled. This avoids problems with
recompiling with the wrong source or target JDK version. Further ant only
recompiles out of date files mentioned on the command line.
When you are testing, sometimes recompiling everything twice is needed to
propagate the new versions to all corners, especially when you have jars or
circular dependencies between packages i.e. A uses
classes of B and B uses
classes of A.
Here are cases where javac.exe fails to
recompile.
- If you recompile A, and A
depends on B (which has not changed) and B
depends on C (which has changed), javac
will not recompile C, if you invoke it on A.
- If you change the value of a final static value in
a class and recompile it, javac won’t necessarily
recompile any other dependent classes which reference that field, and have the
old value burned into the class file as a literal.
- Classes in jars are never updated unless you explicitly update them with jar.exe.
Using a make utility to figure out what needs recompiling usually won’t do
any better. It will take much longer since it will load javac.exe
once per source file. You might as well recompile everything with javac.exe
*.java. Invoking javac.exe once per source file
or even once per directory will really slow you down. It is much better to
invoke javac.exe once, and feed it everything either
via the command line or the programmatic interface, (which is mainly what ant
does for a living).
My rule of thumb is to erase all class files before a full application test or
release. Also erase them if you suspect you are getting an old class file
somewhere along the line. Most of the time, selective recompilation works fine.
Usually you make changes to only one java file at a time before recompiling, and
none of the other files need it. Any time you change public static
final constants is a good time to delete all the class files.
Periodically delete all class files. This cleans up class files from renamed,
and deleted source files. It gets rid of unused anonymous inner class files.
Strange things can happen when you rename a module, and fail to fix all the
references, and still leave the old class file lying about even if you delete
the source.
Circular References
If class A references class B,
and class B references class A,
you have a chicken and egg problem, technically called a circular
reference. If you compile A first, the
compiler won’t be able to find class B. If you
compile class B first, it won’t be able to find
class A. So what you do is compile them both at once
in the same
javac.exe *.java
session and let it sort out the problem, or feed the problem to Ant to sort out.
ANT
ANT compiles so much more quickly than using javac.exe
on the command line, it really is the only way to fly if you have more than a
few experimental student programs. A complete recompile of hundreds of projects
is so quick, that I use it any time I have changed a public
static final or a library used in more than one package.
Don’t spend too much time learning the intricacies of the
javac.exe
command line. It is primarily a student’s tool. As soon as you get serious
and have an actual project, switch to
ANT with
genjar.
Your compiles will be much faster. Your jars will automatically pull in needed
classes from other packages. Your jars will not be stuffed with unused classes.
Your scripts will work unmodified an any platform. Your build scripts will be
easier to maintain. I would even go so far as to say, write a program to write
your ant scripts, so they will all be completely consistent with your latest
thinking.
Learning More
Sun’s JDK Tool Guide to
Javac.exe : available: