VisiComp 1.0 is a software visualization tool that allows
you to observe the inner workings of any Java program while
it's running. Source code for the program under observation
is NOT needed.
VisiComp works with any JDK 1.1 or 1.2 compliant JVM. A free fully-functional demo is available from http://www.visicomp.com
There is a lex equivalent called JavaLex and a yacc equivalent called CUP.
LALR(1) parser JavaLex and JavaCup: http://www.cs.princeton.edu/~appel/modern/java/
Another one, jay, is available from the university of Osnabrück, at http://www.informatik.uni-osnabrueck.de/bernd/jay/.
LL(k) parser JavaCC:
http://www.metamata.com/JavaCC/
ANTLR, an LL(k) parser:
http://www.antlr.org/
LALR(1) parser SableCC from McGill U.
http://www.sable.mcgill.ca/sablecc/index.html
is generously made available under GNU license.
Java Obfuscators replace the original class, field and methods names
in the bytecode with meaningless strings. Second generation obfuscators
are now appearing that also obfuscate the control flow and encrypt
String literals. People use obfuscators on their applets if they want to
hide their code from others. Generally, you wouldn't do this with
software that you put on your website for others to enjoy. It runs
counter to the "open source" philosophy of learning from other's code
and allowing them to learn from yours.
Zelix KlassMaster is a commercially supported obfuscator. It has a
free evaluation version at
http://www.zelix.com/klassmaster/
Another commercially supported obfuscator, with a downloadable
free trial is at
http://www.4thpass.com/SourceGuard/.
There are also some free works from students and others.
http://www.primenet.com/~ej/
Some people have reported problems using these with JDK 1.1.
Obfuscators are intended to foil decompilers. Decompilers translate byte code back into Java source code. Mocha was the first and most well known of the decompilers; it's no longer supported. There is a decompiler (written in C++) at
Because it is in C++, there are different versions for every architecture (hah!) There are also commercial products, such as SourceAgain fromThere's a very good Java Code Engineering and Reverse Engineering FAQ page at http://www.meurrens.org/ip-Links/Java/codeEngineering/.
Use the jar-tool from JDK1.1(.1):
E.g.:
creates a compressed archive. And watch out -- the order of the options ("cvf") determine the order of the arguments!
creates it fullsize (uncompressed) (note the 'O'-option used for JDK1.0.2)
On Unix you can also use:
Info-ZIP home page:
http://www.cdrom.com/pub/infozip/
Latest source code:
ftp://ftp.uu.net/pub/archiving/zip/src/
Netscape's command line version of its JAR packager and signing tool is called "zigbert". They also have a signing tool with GUI written in Java. More info http://developer.netscape.com/software/signedobj/jarpack.html
If you zip your .class files for JDK 1.0.2 (for 1.1 you'll use a Jar):
zip -r0 classes.zip <directories>
<APPLET CODEBASE="."
ARCHIVE=my_zip_file.zip,myOtherZip.zip,thirdfile.zip
CODE="my_main_class.class"
WIDTH=600 HEIGHT=250>
</APPLET>
From JDK 1.1 on, an example of the applet tag used with a jar file is
<APPLET ARCHIVE=myfile.jar
CODE=myapplet.class
WIDTH=600 HEIGHT=250>
</APPLET>
These lines will use an applet called myapplet that can be found in the jarfile myfile.jar. An example applet tag of a jar file used to hold classes in packages is
<APPLET ARCHIVE="myclasses.jar"
CODE="linden.net.MyApplet.class"
WIDTH=480
HEIGHT=120>
</APPLET>
You can supply several jar filenames in a comma-separated list. Jar files are in compressed PKZIP format.
Compiling into native code destroys portability, which is one of
the main benefits of Java.
If you want to create a native executable because you wanted
to make it easy to distribute and use programs,
consider a Jar file instead.
Some companies make products that do this. See the webpages for
NaturalBridge
http://www.naturalbridge.com
,
Symantec
http://www.symantec.com,
JET
http://www.excelsior-usa.com/jet.html
,
Supercede
http://www.supercede.com/,
and Tower Technology
http://www.twr.com/.
The first four are targeted to Microsoft
Windows. Tower Technology supports several flavors of
UNIXTM.
Also, there is a native compiler from IBM, known as the HPJ (High Performance Java) compiler. One user has reported that it created a 2Mb executable from a 12K java file, and did not run any faster. See http://www.alphaworks.ibm.com/
See also Instantiations JOVE
http://www.instantiations.com/jove.htm,
Network World, "Vendors Rush To Speed Java Performance", Feb 9 1998, at
http://www.nwfusion.com/news/0209java.html
Compiling to native code takes away the most significant benefit of Java technology: portability of executables. Further, if you want your Java DLL (or .exe) to interact with C++, you'll have to specify which specific C++ compiler and/or actually compile some sort of linkage via the appropriate C++ compiler. C++ does not have a standard ABI, so there is a big problem with interoperability. Every C++ compiler uses a different object model, a different way of laying out class members, and a different way of "mangling" names for the linker.
C is much simpler. The only question here is how structures are "packed" (i.e., are integers aligned on four-byte bounds?). All the C++ compilers can interact with C code, thanks to 'extern "C"' declarations.
Consider carefully why you want to compile to a native executable, and whether there is a Java way to accomplish your goal. There may be a good reason for compiling to native code, but it needs to be thought through.
Sun has some Performance FAQS for the HotSpot JVM.> See
produces some basic output in a file called java.prof, showing the number of times methods were invoked. The output lines are of the form:java -prof MyClass
| # of calls | method called | called by | time spent |
sort -r +82 <java.prof > java.sortMore and better tools are a third party opportunity. One profiler is JProbe Profiler, available from http://www.klg.com/jprobe/. JProbe is said to be easy to use. Another profiler is OptimizeIt, available from http://www.optimizeit.com/. Each of these profilers has performance tuning, which shows which methods took how much time, and also memory tuning, which shows what objects are in memory and how they were allocated. Both are important things to know. The latest version of the CodeWarrior IDE http://www.metrowerks.com/ has a time-based profiler for Java code. Java WorkShopTM from Sun also has a time-based profiler.
JDK 1.2 comes with some limited profiling capability built-in. Depending on your needs, it may be all that you need. Execute the following to get a short summary of what you can do:
java -Xrunhprof:helpThe columns in the output for -Xrunhprof:cpu=samples are "rank", "self", "accum", "method". For example, you can see which methods are taking the most time to execute, in the context of particular stack traces.
Netscape is unable to find the file or directory named:
/E|/Jwrkshop/JDK/bin/java.lang.Throwable.html
References to the JDK classes assume that all generated html files are in
the same directory and, in fact, that all files for all classes referenced
are generated at the same time. There is no way to generate files
incrementally and have them all reference each other, as you would like.
The javadoc tool in JDK 1.3 does not have this problem. If it cannot link to a class or package, it will not generate a broken link. Additionally, if you use the -link switch, you can link to previously generated HTML files:
javadoc -link http://java.sun.com/j2se/1.3/docs/api/
If the HTML files are currently not available, use the -linkoffline
switch instead of the -link switch, as long as you have a URL that
points to the package list.
Bug Id #4074234 is an RFE for a switch to tell javadoc to generate
documentation for all subpackages within the packages that are listed
on the command line.
The first way is
Another way is
where "tip.java" is a class "at the tip of the iceberg", i.e. that depends on (uses) all the other classes. Typically, this may be your main class. However, "-depend" is known to be buggy and cannot be relied upon. It also doesn't issue compile commands in parallel to make use of multi-processor systems.
Without the "-depend" option, the standard "javac files" doesn't look beyond the immediately adjacent dependencies to find classes lower down the hierarchy where the source has changed.
The -depend options searches recursively for depending classes and recompiles it. This option doesn't help when you have dynamically loaded classes whose names cannot be determined by the compiler from the dependency graph. E.g. you use something like
The author of the code using those classes should make sure that those classes are mentioned in a Makefile.
Your program is not able to find your shared library or DLL.
On Microsoft Windows 95/NT, make sure that the DLL exists in a path that is included within the PATH environment variable. (This need is true for both standard (untrusted) applications and trusted applets. At least, if you use the Java Plug-in to give yourself standard Java inside a browser).
On Solaris, make sure that the environment variable LD_LIBRARY_PATH includes the path of your shared library.
Note that jdb looks for libraries with "_g" appended to their names. Thus, if you intend to use jdb on an application that invokes native methods, you must ensure that the appropriately named libraries are in jdb's path. The "debug" nm libraries can simply be renamed copies of the nondebug libraries.
For example, if your app invokes native methods in a library named mynm.dll (on Microsoft Windows) or mynm.so (on Solaris), make a copy in the same directory and name it mynm_g.dll or mynm_g.so.
It's a known bug in the JDK 1.1.4. The code is:
public class MyDialog {
void Setup() {
addWindowListener( new WindowAdapter() {
public void windowClosing(WindowEvent e) {
myCloseWindow(); }
}
); // anon inner class
}
private void myCloseWindow() { // private outer method
dispose();
}
}
This code sends javac into an infinite loop. The workaround is to make the private method non-private, or to make the inner class a named class. Sun put a workaround in the compiler to silently set the field to package access.
There have been three Java Development Kit releases from Sun so far,
plus a number of
bugfix (dot-dot) releases. The releases are:
They are functionally equivalent, with minor differences in the handling of
default classpath and options supported. To reduce confusion, the jre
command was removed in JDK 1.2. Instead there is a "java" command in
both bin and jre/bin.
jre.exe is the java launcher that comes with the Java Runtime Environment. It ignores the CLASSPATH environment setting in favor of its own internally generated default and whatever is supplied on the cmd line using -cp or -classpath. It's intended to be a bit simpler for those who are only ever running programs, not developing them.
java.exe is the launcher that comes with the JDK. It uses the CLASSPATH environment setting as a starting point and then tacks on its own internally generated entries.
They both serve the same purpose and that's to start a Java VM, have it run a Java technology-based application, then terminate. The source for jre.exe is provided in the JDK. The source to java.exe is provided only in the JDK Source distribution.
Some popular IDEs include:
The command that works in JDK 1.2 is
java -Djava.compiler=NONE ...
This doesn't work in JDK 1.3 which uses HotSpot.
The main reason for turning off the JIT is to get more
information about any exception that is thrown in your code.
But HotSpot is able to produce line numbers in stack traces
even for JIT'd code. HotSpot rocks.
javac writes errors to stderr,
The problem is that DOS doesn't allow stderr to be redirected
(as command.com is very poor software). So you
have to use a special error redirection mechanism in the compiler:
javac -J-Djavac.pipe.output=true myfile.java > errors.txt
In JDK 1.2, you can use:
javac -Xstdout
You typically use this when a compilation produces a lot of error messages,
and they scroll off the DOS window before you can read them.
Alternatively, in WinNT you can get a scrollbar
to appear on a DOS window by changing the properties
with the "Layout" tab. Change the Screen Buffer Size Height: to some
multiple > 1 of the Window Size Height. E.g. use a buffer height of 100 and
screen height of 25 (the default). This will give you three buffers of
scroll "history."
Also in NT, you can write
javac myfile.java 2> errors.dat
For tools that reformat code, try:
For tools that print code neatly, try:
Some Unix utilities work adequately:
Most of the "questions" in this section are diagnostic messages from the compiler. Each answer explains what the message means, and how to avoid it.
The preset memory limit has changed. It went down to 16MB so as not to
penalize low memory machines. You can adjust it with
java -mx128m Frotz # jdk 1.1
java -Xmx128m Frotz # jdk 1.2
to get a 128MB extent.
Also see the Runtime methods freeMemory() and totalMemory().
JDK 1.0 has a limit of 63 words of storage for local variables in any
method. longs and doubles require two words of storage, and all other
primitive types and all reference types require one word. If you assign
values to more than 63 words of local variables, you will get a "Statement
not reached" error on the statement after you assign to the variable that
contains the 64th word. In JDK 1.1, the low limit was removed.
This is one of those error messages where the compiler tries to guess
what you meant, and gives you a message based on a wrong guess! So the
message is confusing.
Your MyOrdinaryClass class implements ActionListener, which means you must include a definition of the methods from the ActionListener interface.
But you did not. You either left a method out, or (more likely) you misspelled its name. Perhaps you wrote "ActionListener" instead of "actionListener".
So the compiler did not find the method to fulfill the interface. Since there was a method promised but not supplied, the compiler thinks you were aiming at an abstract class, and it prints an error message accordingly.
URL test;
try {
test = new URL("http://osprey.avs.dec.com/");
} catch (MalformedURLException e) {
System.out.println("bad URL:" + e.getMessage());
}
System.out.println("this is url " + test);
The compiler will warn you if you use a local
variable before it is certain to
have been initialized since this means
you probably forgot to set it. Recall that class variables and
fields have a default value, but variables declared in a method do not.
In the case of exceptions, you have to consider that the flow of control may terminate abruptly, with no operations completed. In the example above, if an exception is raised in the try clause, variable test will not be assigned a value, yet you are using it after the catch clause.
Always initialize to a value that will work notwithstanding exceptions being thrown.
When you define a constructor for a class, the compiler inserts a call to
the superclass' parameterless constructor unless you explicitly call the
superclass' constructor at the start of your constructor, or you
call another constructor in the same class with this().
So if the
superclass doesn't *have* a parameterless constructor, the compiler emits a
message to that effect. The solution is usually to call the superclass'
constructor at the start of your constructor.
MyApplet.java:11: No constructor matching MyCheckbox(myApplet)
found in class MyCheckbox.
bp1 = new MyCheckbox(this);
^
If a compiler isn't finding a constructor you thought you created, check
whether you gave a return value to the method (remember, constructors have
no return value). E.g.,
public void MyCheckbox( Container parent )
If you did, the compiler will think it is an ordinary method, not a
constructor. This is a common mistake and hard to spot.
public static void main(String[] args) {
^
Statement expected.
public static final float Conversion_Factor = 39.37F;
^
Type expected.
Argument and variable declarations inside methods are never public or
static because they are local to a method. (Before JDK 1.1 they couldn't be
final either, but there was no good reason for that restriction and it was
dropped.) If you have public or static variables, move them outside the
method. They are usually put at the beginning of the class.
The "type expected" error message is also caused by having a statement floating loose outside the body of a method.
T.java:96: Can't access protected method clone in
class java.lang.Object. OtherT is not a subclass of
the current class.
Object.clone() is protected because subclasses might want to restrict
access to cloning, and if Object.clone() were declared public, subclasses
could never make it more restrictive. The subclass can make access to the
clone() operation less restrictive.
This means that a method can clone its own objects, but a method cannot
clone objects of another class, unless you do something like:
class SomeObject implements Cloneable {
public Object clone()
throws CloneNotSupportedException {
return super.clone();
}
}
i.e., override clone() to make it public, and call the superclass clone().
class Foo {
Bar bar;
Foo (Bar b) {
try {bar = (Bar) b.clone();}
catch (Exception e) {}
}
...
class Bar implements Cloneable {
public Object clone()
throws java.lang.CloneNotSupportedException {
return super.clone();
}
}
Another refinement is to note that Object.clone() only throws a
CloneNotSupportedException when the object doesn't implement Cloneable.
Since you control what your classes do and don't implement, you can ensure
that Cloneable classes implement the interface, and you don't need to make
the overridden clone() throw the exception.
public class X implements Cloneable {
public Object clone() { // no throws
try {
// in case members need cloning
X c = (X)super.clone();
return c;
} catch (CloneNotSupportedException e) {
// should not happen, because of Cloneable
throw new InternalError();
}
}
}
"Deprecated" means you are using an older API, that Sun has replaced with
a newer one (usually to follow more consistent naming conventions).
Deprecated methods are not recommended for use. They are
supported in the short term, but your code should be updated with the new.
To update your code, compile your old code using javac's "-deprecation" option
to list deprecated methods, then find the replacement methods in the current
HTML API documentation for the old deprecated methods.
As an example of a deprecated API, Component.size() was replaced
by Component.getSize().
See also
http://java.sun.com/products/jdk/1.1/docs/guide/
misc/deprecation/index.html,
"1.1 Deprecated Methods"
and
http://java.sun.com/products/jdk/1.1/docs/guide/
awt/DeprecatedMethods.html,
"Deprecated methods in the 1.1 AWT"
You need to write it this way:
double cvtDegToRad = Math.PI/180;
double x = 90*cvtDegToRad;
double y = Math.sin(x);
sin is a static method of the Math class that takes radians. You need to
use the "Math" classname, e.g. Math.sin instead of plain sin, because you
have to say what class or object these methods belong to.
A very common mistake is to assume that importing a class means that you don't have to qualify the names of its members. When you call a method you have to state the name of the class or object it belongs to, regardless of any imports you have done. (Except inside the class itself, obviously).
The trig functions are static methods of the Math class, so you give the name of the class in invoking them. Further, the Math class works in radians, not degrees. 360 degrees = 2 pi radians, so use a conversion factor as shown if you are working with degrees.
Your code probably looks something like this:
class myclass {
public static void main(String args[]) {
myMethod();
}
public void myMethod() { //some code
}
}
Static (class) methods can only call without qualification other static
methods, so you either have to qualify the call in (static) main() to
(nonstatic) myMethod() with an object of type myclass, or you have to make
myMethod() static.
People often forget that even though main is "in" myclass, there is no implicit object when you are in main() because it is static. This happens especially when writing code to run an applet as an application, where you want to call init() and start() from main.
public static void main(String[] args) {
Applet ma = new myApplet(); // have to create object
ma.init(); // use to qualify access to non-static methods
ma.start();
}
Note: this pitfall
also applies to non-static fields as well as non-static methods
byte b = 0;
Incompatible type for =.
Explicit cast needed to convert int to byte.
b = b + 100; // compiler error message
b += 100; // works OK
Arithmetic expressions are promoted to the type of the longest, floatiest
operand in them, or at least to int. The first statement involves the
assignment of an expression. The expression is promoted to 32 bits, and
must be cast back down to 8 bits, like this: b = (byte) (b+100);
The second is an operator assignment, and the cast back to byte takes place
automatically. The Java Language Specification says that a compound
assignment expression of the form E1 op= E2 is equivalent to E1 =
(typecast)((E1) op (E2)), where "typecast" is the type of E1, except that
E1 is evaluated only once. (See
JLS
15.25.2 Compound Assignment Operators) The compile-time narrowing of
constants means that code such as:
byte theAnswer = 42;
is allowed, with no cast necessary. (See
JLS 5.2
Assignment Conversion)
Other sites:
JLS 5.2
Assignment Conversion
JLS
15.25.2 Compound Assignment Operators
When the source refers to classes in packages, the CLASSPATH has to point
to the root of the package/directory hierarchy for a reference to resolve
correctly. This is true even for source files in the same package (and
directory). I.e., assuming {class} and {class2} are both in {package},
{class} can't make a reference to {class2} unless the CLASSPATH is set so
javac can find {package}/{class2}.java. It should make no difference what
directory you are in when you invoke javac, unless you are relying on "."
in the CLASSPATH to point to the package root or are specifying the
source file with a relative path (e.g., {package}/{class}.java).
Some examples, assuming
# solaris ksh
$ alias jc=/java/jdk11/bin/javac
$ CLASSPATH=/java/source/
$ jc /java/source/pack/*.java # works fine
$ cd /java/source/pack
$ CLASSPATH=.
$ jc *.java # fails - Foo.java can't find class Bar
$ cd .. # now . is package root, /java/source/
$ jc pack/*.java # works
Javac verifies that a public class is defined in a file of the same name
(e.g., that public class Foo is defined in Foo.java). Two things you can
check:
First, make sure the case matches exactly. public class Foo cannot be in foo.java; it has to be in Foo.java.
Second, are you using MKS on win32? Javac on win32 assumes you are using the DOS path separator (\) even though MKS accepts the Unix path separator (/). When javac tries to parse a your Unix-style path, it won't produce the correct filename, the match will fail, and it will emit an error. You have to use the DOS path separator (\), which must be escaped in MKS - e.g., "javac H:\\source\\package\\Foo.java". Alternatively, you can traverse to each source directory and avoid pathnames altogether.
if (s1 == s2)is giving me funny results.
The comparison using "==" on objects, such as Strings, is asking, "Do these
two objects have the same reference?" Do they have the same address, and
hence are the same object? What you really want to do is ask, "Do these two
Strings have the same *contents*?"
Compare String contents with any of the following:
if (s1.equals(s2) )
if (s1.equalsIgnoreCase(s2) )
if (s1.startsWith(s2) )
if (s1.endsWith(s2) )
if (s1.regionMatches(s1_offset, s2, s2_offset, length) )
if (s1.compareTo(s2) < 0)
(There are other ways, too.)
if ("apple".equals(s2) ) ...
If you compare these the other way round, like this:
if ( s2.equals("apple") ) ...
and s2 is null, you will get a null pointer exception.
Like this.
char c = 'A';
int i = c;
Going the other way is just
c = (char) i;
This question crops up so frequently because the BASIC language
uses functions to map characters into ints, ASC( 'A' ) => 65
causing BASIC programmers to seek the corresponding functions.
The same is true for Pascal, Ada, and other languages.
">>" is a "signed" or "arithmetic" shift, namely, it replicates the sign
bit on the left as it shifts.
The ">>>" operator is an "unsigned" or "logical" shift; it does a shift
right and zero fill. However, ">>>" looks like it does a signed shift with
negative bytes and shorts, where int promotion alters the sign.
This occurs when you have a non-canonical type, byte, or short, with a negative value, e.g.
byte b = -15; // 0xf1
b = (byte) b >>> 4; // why isn't b 0x0f ?
The initial expectation is that an unsigned shift right of 0xf1 would
successively be (in binary)
0111_1000 then
0011_1100 then
0001_1110 then
0000_1111
But that doesn't happen. The rules of arithmetic in the Java
programming language say that all
operands are converted at least to int before the operation (and possibly
to a more capacious type). That means our byte is promoted to an int, so
instead of shifting 0xf1, we are shifting 0xfffffff1. If you shift right
unsigned 4 places, you get 0x0fffffff. When you cast that to a byte it
becomes 0xff, or -1.
The bottom line is that the final result is the same as if you had performed the signed shift because the unsigned shift applied to the intermediate int, not to the original byte. This anomaly means that ">>>" is useless for negative bytes and shorts. It is probably safer and clearer not to use it at all, but to mask and shift instead:
// not recommended
byte b = -15;
b = (byte) (b>>>4);
System.out.println("b= "+Integer.toHexString(b) );
// recommended
b = -15;
b = (byte) ( (b & 0xFF) >> 4 );
System.out.println("b= "+Integer.toHexString(b) );
There are several unexpected things that seem to bite programmers with
floating point. This is almost always a result of the programmer not being
fully conversant with floating point arithmetic in general, rather than
a problem relating to Java technology.
The question of floating point accuracy comes up more than with C++ (for example) because of Sun's decision in the println() method to print enough digits to distinguish the number from the next-closest number, rather than rounding it to 6 significant digits by default as the C/C++ libraries do. [ISO C, Sect 7.9.6.1, line 21 of "the double argument"]
If you seem to be having problems with floating point, the problem probably stems from the fact that floating-point arithmetic is inherently imprecise. You can expect up to 7 digits of precision with floats and 16 digits with doubles. However, that does not mean that a number that can be exactly represented in 7 digits decimal or can be exactly represented as a binary floating point number. On the contrary, that is usually not the case.
Additionally, when Java technology converts floating point numbers to a String, as is done when they are output, enough digits are printed so the number can be read back in with no loss of precision. For this reason, you may see more "inaccuracies" in floating point output than you are used to. You are actually getting more accuracy than on systems (like C,C++) that suppress the less significant digits.
For more information and detailed specifications on how Java deals with floating point, see the URLs listed below.
Other sites:
What Every Computer Scientist Should Know About Floating Point.
See also "the guff from Hough" (numerics ace David Hough) at
http://www.validgh.com/java/
If you want the rounded floating point output that most languages have, use the new java.text package of Java 1.1 to limit the number of digits that are output. If you need more precision than about 16 digits, use the BigInteger and BigDecimal classes of Java 1.1.
Of all the misconceptions about the Java programming language,
this is the most egregious. Far from
not having pointers, object-oriented programming is conducted
in the Java programming language
exclusively with pointers. In other words, objects are only ever accessed
through pointers, never directly. The pointers are termed "references" and
they are automatically dereferenced for you.
"An object is a class instance or an array. The reference values (often just references) are pointers to these objects."Any book that claims Java does not have pointers is inconsistent with the Java reference specification.
Java Language Specification, section 4.3.1.
[emphasis is in the original text]
There is no pointer arithmetic or untyped casting in Java. By removing the ability for programmers to create and modify pointers in arbitrary ways, Java technology makes memory management more reliable, while still allowing dynamic data structures. Also note that Java technology has a NullPointerException, not a NullReferenceException.
A linked list class in Java might start like this:
public class LinkedList {
public LinkedList head;
public LinkedList next;
public Object data;
public LinkedList advanceToNext(LinkedList current) { ...
}
Another choice for a linked list structure is to use the built-in class
java.util.Vector which accepts and stores arbitrary amounts of Object data
(as a linked list does), and retrieves it by index number on demand (as an
array does). It grows automatically as needed to accommodate more elements.
Insertion at the front of a Vector is a slow operation compared with
insertion in a linked list, but retrieval is fast. Which is more important
in the application you have?
All parameters (values of primitive types and values that are references to
objects) are passed by value.
However this does not tell the whole story,
since objects are always manipulated through reference variables in Java.
Thus one can equally say that objects are passed by reference (and the
reference variable is passed by value). This is a consequence of the fact
that variables do not take on the values of "objects" but values of
"references to objects" as described in the previous question on linked
lists.
Bottom line: The caller's copy of primitive type arguments (int, char, etc.) _do not_ change when the corresponding parameter is changed. However, the fields of the caller's object _do_ change when the called method changes the corresponding fields of the object (reference) passed as a parameter.
A feature introduced in JDK 1.1. They are literals of type "Class" that
hold a value representing any class. There are even values to represent
"void" and an array, like this:
Class myCl1 = Character.class;
Class myCl2 = Void.class;
Class myCl3 = Object.class;
Class myCl4 = String[].class;
Class myCl5 = int[][].class;
You might use it like this:
Class cl = thing.getClass();
if (cl.equals(myCl1))
System.out.println("It's a Character class");
Note that a class literal
Component.class
is the equivalent of
Class.forName("java.awt.Component")
The second can throw an exception, but the first cannot. If you don't know
the name of the class when you write the code, you cannot use the first
form.
The naming conventions are straightforward:
import java.rmi.server.*;
...
RemoteObject ro;
versus:
java.rmi.server.RemoteObject ro;
No, it makes no difference to the class files or runtime speed. Import is
just a shorthand for quoting the full name package and class name (as in
the examples in the question). Importing a class does not cause the class
to be loaded at run time. There is no runtime penalty for using the * form
of import. The class file will contain the name of the packages it uses,
and the loader will look for those classes as needed at runtime.
At compile time, the different forms of import may or may not make a difference to compile time. Such a difference is likely to be negligible, and should not be a factor in which form of import you use.
However, there are style advantages. Some say that stating which classes you are importing can help program readability. In a program with many * import statements, it may take a programmer time to find which package an obscure class is imported from. If you explicitly list each class you import at the top of the program, you document which package each class you use comes from. These people suggest that you use
import java.rmi.server.RemoteObject;
in preference to:
import java.rmi.server.*;
Other people say that it is clearer still to use the full package and class
name, at the point where you use classes in other packages.
java.rmi.server.RemoteObject ro;
But that gets a little lengthy when you instantiate:
java.rmi.server.RemoteObject ro
= new java.rmi.server.RemoteObject();
You always have the option of stating the full package and class name,
whether you use import or not.
Another good reason not to use the * form is when you are importing two packages that have classes of the same name and you want to use only one of those classes. E.g.
import com.sun.*;
import com.ms.*;
where there is a class called Modem in both those packages. If you use
the * form of import, you import both of the Modem classes and then
must fully qualify the class each time you use it, to say which of the two
you mean. In Java 1.2, the class java.util.List was introduced. That
had the same unqualified name as java.awt.List. If your code had
"import java.awt.*; import java.util.*;" it would no longer compile. You'd
get a message about ambiguous classname. If you import all of a package
indiscriminately you might get bitten when the package API changes.
In Java 1.0, if you import a class that has the same name as a class defined in that source file, you will get an error that the class names clash. In Java 1.1, the local class will be used when the package name is not given; to use the imported class, you have to use the full package name.
The best advice is to write the program so that it is as readable as possible. Where you have a group of well-known classes, as in java.awt, there is no reason not to use "import java.awt.*;"
No. There is no good alternative. There are several bad alternatives:
import java.lang.Math.*;
double sin(double x) {
return Math.sin(x);
} // etc. for each function
But you'd have to use your class name everywhere but inside your class,
so it doesn't help.
java.lang.Math M = null;
angle = M.cos(i);
Besides not being clear, this invites abuse and errors.
- You could inherit the names
If java.lang.Math were not final and your class did not extend another
class, you could have your class extend Math, to bring the namespace
in. However, it is poor OOP style to use inheritance to obtain a name
abbreviation rather than to express a type hierarchy.
JNI is the Java Native Interface. It defines the way that a Java
technology-enabled program
can call C programs. The industry has agreed on, and Sun has codified, JNI
as the standard. Microsoft shuns the standard and uses a protocol of its
own called Raw Native Interface, RNI.
You might think that once a program uses JNI, portability is lost, and hence it doesn't matter if vendors diverge from the JNI standard. Not so. Code that accesses a native library using JNI can run on any VM that supports JNI, so it's portable across VMs on the same platform. Further, you can port a native library to all platforms Java supports (indeed, this is how Sun implements the Java Platform), so JNI _enables_ cross-platform development where it's necessary to use platform-specific idioms for certain functionality.
Conversely, code that uses RNI can only run on Microsoft's VMs on the win32 platform. Microsoft's RNI has the effect of limiting RNI programs to the Microsoft VM. Further, Microsoft's failure to support JNI locks out JNI-based functionality on Windows. Microsoft's non-standard RNI is the reason that programs using the Microsoft JVM cannot use the standard Java jdbc-odbc library. That library has a piece written in C. It works for all JVMs except Microsoft's.
The standard JNI thus has two purposes:
Taking the questions one at a time.
Use of JNI detracts from program portability. So you would only
do it when you need some critical single-platform effect. The documentation
on JNI is at:
http://java.sun.com/docs/books/tutorial/native1.1/index.html
If your interest extends to reading a book on JNI, a good one is "Essential JNI Java Native Interface" by Rob Gordon; ISBN 0-13-679895-0.
In general, if you want to find out about topic "X" in Java, your first stop should be to search the http://java.sun.com website for "X". For example if you want to know about Internationalization in Java, a search at the site quickly takes you to http://java.sun.com/products/jdk/1.1/docs/guide/intl/intlTOC.doc.html.
Java programming language doesn't have unsigned ints.
The reason is that this is a poorly
designed area of C. The rules for what type you end up with when you mix
signed and unsigned in expressions are complicated, and they changed
between K&R and ANSI C (you might have heard this under the name
"unsigned preserving vs. value preserving"). Worse, they depended on the
underlying hardware, so they varied from platform to platform, causing bugs
in all kinds of unexpected places. The book "Expert C Programming" goes
into this in more depth (page 25). So, to avoid bringing over the hidden
complexities, the Java programming language
does not bring over unsigned types from C.
Use type char if you are OK with 16-bit unsigned quantities. Otherwise, go to the next larger type and use masking. If you don't have to worry about division by numbers with the high bit set, then when you use >>> for right shift and remember to AND each byte with 0xFF where they are being expanded into a larger type, then there is no difference in the bit patterns generated.
Specifically, to convert an int to its unsigned representation, use:
((long)i) & 0x00000000FFFFFFFFL
This promotes the signed (and possibly negative)
int to long (with sign extension) then chops off the sign-extension,
leaving it as the same 32-bit quantity held in a 64-bit type.
It first appeared in JDK 1.0 FCS (it had not been in the betas). Then it
was removed in JDK 1.0.1. It was an ugly hack syntax-wise, and it didn't
fit consistently with the other access modifiers. It never worked properly:
in the versions of the JDK before it was removed, calls to private
protected methods were not dynamically bound, as they should have been. It
added very little capability to the language. It's always a bad idea to
reuse existing keywords with a different meaning. Using two of them
together only compounds the sin.
The official story is that it was a bug. That's not the full story. Private protected was put in because it was championed by a strong advocate. It was pulled out when he was overruled by popular acclamation.
Some use a semantic distinction:
an abstract superclass models the "is" relationship,
while an interface models the "has" relationship. The rule would be, if
it's a subtype, inherit; otherwise, implement.
But, in the absence of real-world characteristics to distinguish the objects from their properties and parents, that becomes a circular argument. In this case, you have to look at the practical differences in Java (compared with C++).
Most differences between interfaces and abstract classes stem from three characteristics:
In greater detail, these topics are:
Other differences to consider:
Static (per-class, rather than per-object) methods do not participate in
overriding (choosing the right method at runtime based on the class of the
object). Probably the best and simplest way to think about this (and to
write your code) is to write every invocation of a static method using the
fully qualified class name:
class A {
public static method1() {
A.method2();
}
public static method2() {
}
}
class B extends A {
public static method3() {
A.method1();
}
public static method2() {
}
}
Now it is perfectly clear that the static method2() that is called is
A.method2(), not B.method2(). A.method2() will be called regardless of
whether you use the fully-qualified class name or not, but using "A." makes
it obvious to all.
Being final guarantees that instances of String are read-only. (The String
class implements read-only objects, but if it were not final it would be
possible to write a subclass of String which permitted instances to be
changed.) Strings need to be read-only for security and efficiency.
As for efficiency, Strings are very commonly used, even behind the scenes by the Java compiler. Efficiency gains in the String class yield big dividends. If no one can change a String, then you never have to worry about who else has a reference to your String. It's easier to optimize accesses to an object that is known to be unchanging.
Security is a more compelling reason. Before String was changed to be final (while Java 1.0 was still in beta) there was a race condition which could be used to subvert security restrictions. It had to do with one thread changing a pathname to a file after another thread had checked that the access was permitted and was about to open it.
There are other ways to solve these problems, but the designers preferred making String final, particularly since the StringBuffer class is available as an alternative.
"Constructor declarations are not members. They are never inherited and
therefore are not subject to hiding or overriding." The default constructor
is not inherited, but provided. (See
JLS
8.6.7 Default Constructors)
If you don't give your child class any constructors, a default no-arg constructor that invokes the superclass' constructor is provided for you. If the superclass doesn't have a no-arg constructor, you should create a constructor and call the appropriate superclass constructor.
Also in the FAQ:
Compiler message
No constructor {superclass}()
Other sites:
JLS
8.6.7 Default Constructors
Generic programming in java (the rough equivalent of C++'s templates) works
reasonably well since all java classes are subclasses of Object. There is,
however one potential problem - there is always a possibility that a
generic container may contain different classes of objects.
This naturally leads to the question of how to do this in a type-safe way. If you've created a generic LinkedList class, how can you be type safe without having to create a multitude of subclasses (IntegerLinkedList, StringLinkedList, etc.)?
Generics are coming to Java, probably to JDK 1.4 (whatever it ends up being called. See bug id 4064105 at the Java Developer Connection.
One way to handle this in the absence of generics would be to offer up an additional constructor in your generic class that takes a parameter of type "Class" and uses that parameter along with Class's "isInstance" method to guarantee that Objects added to the container are the expected type.
public class LinkedList {
Protected Class type = Object.class;
public LinkedList(Class type) { this.type = type; }
public void addElement(Object element) throws Exception
{
if(!type.isInstance( element ))
throw new Exception(
"Expected element of type (" + type + ")" +
" got element of type (" + element + ")" );
...
}
}
foo("A param",
new Object[] {"param3", "param4", new Integer(5)} );
// ...
void foo(String param1, Object param2[]) {
System.out.println(param1);
for (int i = 0; i < param2.length; i++) {
System.out.println(param2[i].toString());
}
}
You can even pass arrays of arrays using this method. Of course, inside
the method you need to be able to decode what the arguments are and how
you use them.
However, remember the wise words of Professor Alan Perlis, "if your procedure has more than about half a dozen parameters, you probably forgot a few." Passing large numbers of arguments into a function suggests your function is badly organized.
There are two ways. The obvious way is "just add another level of
indirection". Wrap the object in another class, whose purpose is simply to
be passed as a parameter, allowing the nested object reference to be
modified.
The second alternative is a clearer variant of this. Pass in a single
element array. Since arrays are objects, this works.
void jfoo(Object ref[]){
ref[0] = new Object();
}
...
Object kludge[] = new Object[1];
kludge[0]= myObj;
jfoo(kludge);
if (kludge[0] == myObj) ...
else ...
Note that changing a global variable/object inside a method is an egregious
programming practice; it usually violates basic OOP constructs.
You can just have the function return a Vector. This is particularly
convenient when you're not sure how much you are going to be returning,
based on what occurs in the method. A Vector is essentially a
dynamically-growable array. Regular arrays can't grow after you declare
them - you have to declare a bigger array and move the old stuff into it.
There are several ways. If you want a rectangular array, you can allocate
the space for the array all at once. The following creates a 4x5 array:
int arr[][] = new int[4][5];
If you want each row to have a different number of columns, you can use the
fact that a two-dimensional array is actually an array of arrays. The
following code allocates a triangular array:
int arr[][] = new int[4][]; // allocate the four row arrays
for (int i = 0; i < 4; i++) // initialize each of the four rows
arr[i] = new int[i + 1]; // row i has i + 1 columns
Note that if you allocate an array of any kind of object (as opposed to
primitive type), all the references will be null by default. These null
references can result in NullPointerExceptions if you try to dereference
them.
int arr[] = new int[4];
you can say
if (arr[2] == 0)
But after doing
Integer Iarr[] = new Integer[4];
you must fill in the object reference before using it. E.g.,
Iarr[2] = myInt;
or
arr[2] = new Int(27);
before you can say
if (Iarr[2].equals(myInt))
If the array only contains primitive types or if you want to copy only the
object references (i.e. a shallow copy), not duplicate the objects,
then use the method
java.lang.System.arraycopy(Object src, int src_position,
Object dst, int dst_position, int length);
Otherwise, if you want to duplicate the objects (i.e. a deep copy), you have to initialize
your new array and write a loop that duplicates each object in the old
array into the new.
Note that the documentation for arraycopy() says that if src and dst refer to the same object, then arraycopy behaves as if the source array elements are copied into a temporary array (i.e., they are preserved). Some (wrongly) interpret this as meaning a temporary array will be so allocated, but that's not necessarily the case.
Other sites:
JLS 20.18.16 {java.lang.System.arraycopy()}
When you allocate an array, the elements are set to their default values,
but that doesn't help when you want to reuse an array.
The class java.util.Arrays (new in JDK 1.2) provides
methods for clearing/filling arrays: java.util.Arrays.fill(array, 0)
performs the same task as the code below.
If you want to set an array to the same set of varied values many times, create a "mastercopy" array which is final. Initialize it with the values, then use System.arraycopy() to copy it into the work array each time you need to set the work array.
In Java 2, you can use one of the fill() methods in java.util.Arrays.
There is a variant for each primitive type, including some that fill
a range in the array. It currently just does it one by one in a loop.
Using a loop that does it one by one is probably 20 to 40 times slower than
good old memset() in C.
A fast way on many VM's is to set the first byte of the array, then use System.arraycopy() repeatedly to fill the next byte, the next two bytes, the next four bytes, the next eight bytes, etc., and when you get past halfway, fill in the rest.
public static void bytefill(byte[] array, byte value) {
int len = array.length;
if (len > 0)
array[0] = value;
for (int i = 1; i < len; i += i)
System.arraycopy( array, 0, array, i,
((len - i) < i) ? (len - i) : i);
}
This is faster on Sun's VM than a simple loop, and probably even faster
under JITs because it only performs at most log2(array.length) bounds
checks. This is a clever code idiom applying the binary chop algorithm to
arrays even when their size is not a power of 2.
When you declare an "array", you are really only declaring a reference
to an array. To get an actual array, and start filling the
elements, you must then allocate it with new.
The following code:
int[] ia;
ia[2] = 2;
Throws a NullPointerException because ia is null.
You must allocate the array before using it:
int[] ia = new int[3];
ia[2] = 2;
You can't. Once an array is created, its length cannot be changed.
You can allocate a new array, copy the elements into the new array,
and set the reference to the original array to point to the new array:
Object[] oa = new Object[3];
// ... Now I want to make the array bigger:
Object[] noa = new Object[5];
System.arraycopy(oa, 0, noa, 0, oa.length);
oa = noa;
If oa is the only reference to the original array, it is now
available for garbage collection.
Often, using Vectors or ArrayLists is easier than resizing arrays
manually; those classes effectively encapsulate the array resize and
copy code shown above, but also add many convenience methods for
searching, iterating over elements, and performing set operations.
When you put a reference into an element of an array, you do not
need to know what kind of array the array reference you're using
is pointing to, nor what kind of object the reference you're
inserting is pointing to! (E.g. You may have an Object[] which
you set up at runtime to point to, e.g. a Number[2] array.
See the code below.)
You (and the Java compiler) know the types of the two references,
but the (sub)classes of objects they are pointing to may not be known
until run time.
As long as the reference you are putting into the array is compatible with what the array itself actually is (not the reference to the array), the insertion will work. If the two are not compatible, an ArrayStoreException will result. Consider the following code:
Object[] oanr = new Number[2];
Object oi = new Integer(2);
oanr[0] = oi;
This works, because oanr points to an array of Number references,
and oi is a reference to a Integer object, and Integer is a
subclass of Number.
Contrast that example to this code:
Object[] oanr = new Number[2];
Object os = "String";
oanr[0] = os;
This will throw ArrayStoreException because oanr points to an
array of Number references, but os points to a String, and
String is not a subclass of Number.
Actually, you don't even need to know the type of the Array reference
if you use the set() method of java.lang.reflect.Array:
Object oa = new int[2];
Object oi = new Integer(2);
Array.set(oa, 0, oi);
In this example, the set() method unwraps the int value from the
Integer and stores it in the int array.
You have to know what it means to cast from one array type to another,
Such a cast applies to the reference to the array;
the cast does not apply to the
elements of the array. You cannot cast a reference to an array of longs
into a reference to an array of ints, because the array itself remains
an array of longs. Java does not allow you to cast a reference to
an array of primitives to a reference to an array of any other type.
Instead of casting the array reference, you can make a new array and cast the elements as you copy them into the new array. Note that you must write a loop for this yourself; System.arraycopy() will not copy an array of one primitive type to an array of another type.
You have to know what it means to cast from one array type to another.
Such a cast applies to the reference to the array;
the cast does not apply to the elements of the array.
The cast will fail if the array object is not the same class or a subclass of the type you are casting to. As with all casts of references, if the object the reference is pointing to is not of the correct class, a ClassCastException is thrown.
In the following code:
Object[] oasr = new String[2];
oasr[0] = "String";
String[] sasr = (String[]) oasr;
The cast is successful because the array itself is of class String[],
even though the reference we are casting is of type Object[].
Object[] oaor = new Object[2];
oaor[0] = "String";
String[] sasr = (String[]) oaor;
In this case, the array itself is of class Object [], as thus
a reference to the array cannot be cast to String [], because
Object is not a subclass of String.
If you want to convert an array of Superclass references to an array of Subclass references, you can use System.arraycopy():
String[] sasr = new String[2];
System.arraycopy(oaor, 0, sasr, 0, oaor.length);
If you want to convert a collection into an array of references
to a subclass of Object, you can pass an array of that type to
the toArray() method, and you will get back an array of the same
type:
List list = new ArrayList(Arrays.asList(oaor));
String[] sasr = (String[]) list.toArray(new String[list.size()]);