Monday, September 8, 2008

Making Java Signatures Simple

Methods have names. For example, System.out.println() is usually called "print line", though we'd probably say "system-out-print line" for it as I've written it here.

Unfortunately, the word "name" doesn't have a technical meaning. And even if we gave it one, it might lead to misunderstanding when we're switching back between technical terms and nontechnical ones. So there's a technical term for names of methods in Java: signatures.

The way we've used "name" above refers to the same thing as the Java term "simple signature." The simple signature of a method is its text name, ignoring everything in the parentheses, its return type, and so on. So println() and println(String) have the same simple signature.

The full signature, which is what we mean when we just say "signature", includes the full typing of the method and its parameters. So the full signature includes the type or class of everything in the parentheses of the method as well as the name of the method. This is what Java looks at when it's compiling.

That's why you get a runtime error if you do the following:

public static void main(){

The Java compiler will compile this just fine. It will create a .class file with a method that's got the signature main().

Then when you try to run it, the JRE will look for a method with the signature main(String[]), that is, a method with the text name main followed by a parameter list that includes an array of strings. If the array of strings isn't there, it doesn't match the signature that the JRE is looking for. So you get an error when you try to run your program. This will also happen if you do this:

public static void main(String arg){

You've got a method whose signature is main(String) not main(String[]), that is, its parameter is a String, not an array of Strings.

An example of methods that have the same name but different signatures are the constructor methods for the Color class. You can create a new Color in any of several different ways:

Color(int r, g, b)
Color(int r, g, b, a)
Color(int rgb)
Color(float r, g, b)

and so on.

In the first we give the constructor three different integer values for the red, green, and blue values of the new Color. In the second we give four integer values--the same three as before plus an alpha (transparency) value. Or we can pass one integer value that has all three of the red, green, and blue values in one number. Or we can pass separate red, green, and blue values as floating point numbers rather than integers. There are more ways, yet.

While all these constructors have the same name, or simple signature ("Color"), they each have a different signature based on their parameter list. That way Java is able to tell them apart, and know what value types it should expect to work with. That way if you give two values as integers, and a third as a floating point value Java will realize it doesn't know how to deal with that and recognize an error in the code.

That means when you're calling a method, and the compiler spits it out and says it's not found you need to make sure you've:
  1. spelled the name right,
  2. got the right type and number of parameters,
  3. and imported the appropriate packages and classes.