ACME Java FAQ

Here are some common mistakes and questions.

  1. "What's a 'method verification error'?"
  2. "How do I call an applet in a different directory? CODE=../MyApplet doesn't work."
  3. "My xxx method never gets called!"
  4. "Why can't I say just abs() or sin() instead of Math.abs() and Math.sin()?"
  5. "I changed my applet and did a Reload, but it still gives me the old version!"
  6. "How do I format numbers? I don't see anything like printf()."
  7. "How do I load images / sounds into an application, not an applet? It gives me a NullPointerException in getAppletContext."
  8. "How do I do callbacks when there are no function pointers?"
  9. "I made my class Cloneable but I still get 'Can't access protected method clone'"
  10. "How do I get my Java application to do its web accesses through a proxy?"
  11. "What's the difference between notify() and notifyAll()?"

"What's a 'method verification error'?"

Compiling a single .java source file can produce more than one .class bytecode file. This is because, of course, a source file can contain more than one class. However, the compiler doesn't tell you it's producing multiple output files. You have to remember to check for them and copy them all to the web directory. If you don't, and just copy the primary .class file, you get the mysterious method verification error when you try to run the applet. There are other reasons for this error, but that's the most common one.


"How do I call an applet in a different directory? CODE=../MyApplet doesn't work."

The CODE= value in an APPLET tag is not a URL or even a simple filename. It's a class name. It cannot have a hostname in it; it cannot even have a ../. If you want to use a ../ or a different hostname, it has to go in a CODEBASE= value. The implication is that all class-files for a given applet must always come from a single directory - thus you can't have utility classes in a central directory and call them from classes located elsewhere. You're pretty much forced to keep your entire set of class-files in one central directory.


"My xxx method never gets called!"

If you've tried to define one of the methods that's supposed to get called back, such as paint() or mouseDown(), but it never actually gets called, what has probably happened is that your declaration was not quite right. For instance, maybe you declared your paint() but forgot it takes a Graphics as parameter. The Java compiler is happy to create the method for you, but since the signature doesn't match, it won't override the default method in the parent class. The default method is still getting called instead of your method. This is actually a general problem with most polymorphic languages - C++ has it too.


"Why can't I say just abs() or sin() instead of Math.abs() and Math.sin()?"

The import statement does not bring methods into your local name space. It lets you abbreviate class names, but not get rid of them altogether. That's just the way it works, you'll get used to it. It's really a lot safer this way.

However, there is actually a little trick you can use in some cases that gets you what you want. If your top-level class doesn't need to inherit from anything else, make it inherit from java.lang.Math. That *does* bring all the methods into your local name space. But you can't use this trick in an applet, because you have to inherit from java.awt.Applet. And actually, you can't use it on java.lang.Math at all, because Math is a "final" class which means it can't be extended.


"I changed my applet and did a Reload, but it still gives me the old version!"

Yep, in Netscape Navigator at least, hitting Reload will not reload an applet. The first copy you load stays there until the Java Virtual Machine exits. You can accomplish this by exiting and restarting Navigator. In previous versions of Navigator you could also force an applet reload by hitting Back until you no longer had any Java-enhanced pages on your history stack, and then waiting two seconds; but this no longer works in Navigator 3.0, because Java class files are now cached. That's a good thing, but it's too bad that the Netscape folks didn't also fix Reload at the same time.


"How do I format numbers? I don't see anything like printf()."

Yep, there's no equivalent of printf() in the standard classes. I wrote one, though; it's called Acme.Fmt. The doc also includes pointers to a couple similar classes elsewhere on the net.


"How do I load images / sounds into an application, not an applet? It gives me a NullPointerException in getAppletContext."

What you probably did to make your application is just create a Frame and stick an Applet into it. Some of the Java books mention this as the right way. Well, it's not really. That suffices if you're doing real simple stuff, but as soon as you try to use images or sounds or getDocumentBase or parameters or the status line, you're out of luck. What your Frame lacks is an AppletStub and an AppletContext. Fortunately, you don't have to figure out what those are, cause I've done it for you. See Acme.MainFrame - it lets you add a trivial main program to any applet and run it as an application.

Alternatively, if you don't want to write your application as an Applet at all, you can get yourself a Toolkit and use it directly instead of through AppletContext. Toolkit.getDefaultToolkit() is one way to do this, although if you're not going to be doing any GUI stuff you might want to use Acme.JPM.StubToolkit.


"How do I do callbacks when there are no function pointers?"

There are at least two different ways to define a class that calls back to routines in the client:


"I made my class Cloneable but I still get 'Can't access protected method clone'"

Yeah, some of the Java books, in particular "The Java Programming Language", imply that all you have to do in order to have your class support clone() is implement the Cloneable interface. Not so. Perhaps that was the intent at some point, but that's not the way it works currently. As it stands, you have to implement your own public clone() method, even if it doesn't do anything special and just calls super.clone(). See Acme.GenericCloneable for a sample clone routine.


"How do I get my Java application to do its web accesses through a proxy?"

It's pretty simple, although it's not documented in any obvious place. Just add the following command-line arguments when you start the application:


-DproxySet=true -DproxyHost=hostname -DproxyPort=portnum

"What's the difference between notify() and notifyAll()?"

The following is paraphrased from DEC SRC Research Report 20, "Synchronization Primitives for a Multiprocessor: A Formal Specification":

notify() is used to unblock one waiting thread; notifyAll() is used to unblock all of them. Using notify() is preferable (for efficiency) when only one blocked thread can benefit from the change (for example, when freeing a buffer back into a pool). notifyAll() is necessary (for correctness) if multiple threads should resume (for example, when releasing a "writer" lock on a file might permit all "readers" to resume).

Back to ACME Java.
Back to ACME Labs.