Showing posts with label signature. Show all posts
Showing posts with label signature. Show all posts

Tuesday, January 25, 2011

Java's File Names and Class Names

Java is picky about the file names you use.

Each source file can contain one public class. The source file's name has to be the name of that class. By convention, the source file uses a .java filename extension (a tail end of a file name that marks the file as being of a particular type of file.)

So, for a class declared as such:

public class HelloWorld{
...

The file it is stored in should be named HelloWorld.java.

The capitalization should be the same in both cases. Some operating systems don't notice whether file names are capitalized or not. It doesn't matter, you should be in the habit of using the correct capitalization in case you work on a system that does care about capitalization.

When you compile your file with javac, you pass the full file name to javac:

javac HelloWorld.java

Let's say we save the file under a different name. We write the following program:

public class HelloThere{
public static void main(String arg[]){
System.out.println("Hello There.");
}
}

Then we save it as HelloWorld.java, and try to compile it:

>javac HelloWorld.java
FileName.java:1: class HelloThere is public, should be declared
in a file named HelloThere.java
public class HelloThere{
^
1 error


Java lets us know that it won't compile until we rename the file appropriately (according to its rules.)

So let's rename the file. Let's call it HelloThere.javasource. Seems a bit more explicit than just .java, right? Let's run the compiler:


>javac HelloThere.javasource
error: Class names, 'HelloThere.javasource', are only accepted
if annotation processing is explicitly requested
1 error

Java's still not happy with us. Annotation processing? That's when we include extra information in the program about the program itself. We're not bothering with that just now. So we should just name the file HelloThere.java, and not get fancy with our file names.

But, under the right circumstances, javac does allow file name extensions other than .java. That's why we always type in the full file name, including .java, when we use javac. We say 'javac HelloThere.java', not just 'javac HelloThere'. Javac can't assume that we mean a .java file, though that's what it will usually be.

The Class File

Once we make javac happy with a proper file name, and a program with no errors, javac produces a new file. This file will have the original file name, but with .java replaced with .class. This is your bytecode file, the file that the Java Virtual Machine can run.

When we run the program with Java, we're running the .class file. In the case of HelloThere, we're running the HelloThere.class file. But we don't type in the full file name. Why?

Unlike javac, java requires a .class file. That's all it will work with. There's no opportunity to have a different extension to the file name. So it assumes the .class part of the file name. But that's not the whole story.

If you add .class yourself, here's what you'll get:

>java HelloThere.class
Exception in thread "main" java.lang.NoClassDefFoundError:
HelloThere/class
Caused by: java.lang.ClassNotFoundException: HelloThere.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:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)

Pretty ugly. What we're actually doing when we type "java HelloThere" is telling Java to run the class HelloThere. Java assumes that it will find this in a file called "HelloThere.class", so that's what it's looking for first.

We're not telling Java to run the file HelloThere.class, we're telling it to run the class HelloThere, which it expects to find in the file HelloThere.class.

But what if we ask for another class that doesn't have its own .class file?

Just for fun, let's change HelloThere.java like this, and see what happens:
public class HelloThere{
public static void main(String[] arg){
System.out.println("Hello.");
}
}

class HelloZoik{
public static void main(String[] arg){
System.out.println("Zoiks!");
}
}

After we edit it, we compile with 'javac HelloThere.java' and hold our breath.

Hurray! No errors!

Now we have a second class, HelloZoik, in the HelloThere.class file. Can Java find it?

Let's try:
 java HelloZoik
Zoiks!

It worked! Java found our class inside HelloThere.class.

This shows it's not the file name that we're calling with the 'java' command, it's the class name.

If Java doesn't find the class inside a file with the same name as the class followed by .class, it'll look in the other .class files available.
StumbleUpon

Friday, August 13, 2010

Multiple Constructor Methods

A special type of method that creates an instance of a method is called a Constructor Method. When an object has member variables that are objects, we need to define a constructor method to set up those variables. We'll show how to do that here. If you want a more basic introduction to constructor methods, you may want to take a look at my prior article.

As an example, we're going to create a simple class of object for use with my simple video game kernel in a new version I'll be introducing in an article in the near future. The class definition consists mostly of constructor methods, since the class itself is presently not much more than a Rectangle with an added field.

import java.awt.*;

// A Simple class for use in the simple video game examples.
// Mark Graybill, Aug. 2010

public class Brick extends Rectangle{
Color brickColor;

public Brick(int newX, int newY, int newWidth, int newHeight){
super(newX, newY, newWidth, newHeight);
brickColor = new Color(0, 128, 255);
}

public Brick(int newX, int newY){
this(newX, newY, 10, 10);
}

public Brick(){
this(0,0,10,10);
}

public void setColor(Color newColor){ brickColor=newColor; }
public Color getColor(){ return brickColor; }

} // End Brick

In this class, we have three forms of constructor, each with a different set of parameters. The one that takes the most parameters is the "base" version. It starts with a call to super(). This calls the constructor for Brick's superclass, or parent class, Rectangle. A look at the documentation for Rectangle shows that it has a constructor that takes four integer arguments, as we use here in super().

When we use super(), it must be the first thing we do within our constructor method. If we don't use super(), Java will do it automatically as the first thing in a constructor, calling it with no parameters. Since we want to set values for our inherited fields of x, y, width, and height it's better to call super() with those parameters. Otherwise, we could just as well have done something like this:
  public Brick(int newX, int newY, int newWidth, int newHeight){
x=newX;
y=newY;
width=newWidth;
height=newHeight;
brickColor = new Color(0, 128, 255);
}

This would have the same effect, and Java would insert an invisible call to super() in front of x=newX;.

The other constructors use the first method. To do this, they use another special method that's like super(). It's called this(), and it calls another constructor for this class. We can't do a call to Brick(), if we try, the compiler will see it as an undefined symbol:

>javac Brick.java
Brick.java:11: cannot find symbol
symbol : method Brick(int,int,int,int)
location: class Brick
Brick(0,0,10,10);
^
1 error

So we use this() instead.

Like super(), the this() method must be the first thing called in the constructor method's body. Since don't call super()--it's in the base constructor--so there's no conflict about which goes first. If you use this(), you don't use super().

By using this() with the other constructor methods, we can keep all our key code code for the constructor in one place. If we had each constructor setting member values and constants without calling the base constructor method, then we'd end up with repeated code--a prime opportunity for bugs to enter our code if we update the code in one place, but not another. We don't want repeated code! Multiple independent constructors are used in the Java Tutorials, but I expect they're used to keep the lesson simple, not because they are a good coding practice!

You can find out more about this() and super() in the Java Language Specification, under Explicit Constructor Invocations.

You can probably see that I should really have my base constructor allow a Color to be passed to it, too. Try adding this yourself as an exercise to try out your understanding of constructor methods, then see what javac thinks of your work.
StumbleUpon

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.
StumbleUpon

Thursday, July 3, 2008

Constructor Methods

A constructor method is a method that creates an object. To create the object, it uses the class as a sort of blueprint for what member variables the object has, what instance methods, and so on.

The name of a constructor method is the same as the name of the class. For example, if we have a class named Dragon its constructor will be named Dragon as well:
public class Dragon{

  public Dragon(){
    super();
  }
}

There are a couple of things to notice here. One is that, unlike a regular method, the first character is upper-case, just like the class name. The constructor name must exactly match the class name. While it is only a convention that classes (and therefore, their constructor methods) start with a capital letter, it is an iron-clad requirement that the constructor name match the class name.

The other thing you'll want to notice is that there's no type given in the method declaration. A normal method (called an instance method, if we want to get formal) has a type provided in its declaration, just as a variable has a type in its declaration:
public void dragon(){ }    // Instance Method.
public int dragonCount;    // Instance Variable.
public class Dragon{ }    // Class.
public Dragon(){ }    // Constructor.
In the constructor's declaration, there's a scope called out (public) but no type. This is because, as a constructor for the object, it will be returning an object of the type it is a constructor for. OK, that sounds worse than it is. Let's try again...

A Dragon constructor returns a Dragon object. A String constructor returns a String object. That's what it constructs, so that's what it returns. Declaring a type would be redundant:
public Dragon Dragon(){ }    // This is NOT correct code, just an example of silliness!

A Subtle Error

If you accidentally have a typo in your program that results in your class and constructor having different names, the compiler will complain that you've got a method without a type declaration. You'll look at the code and say "Hey! That's a constructor. It doesn't need a type declaration! What is my compiler smoking?"
public class Dragon{

public Dragin(){
super();
}
}

Dragon.java:3: invalid method declaration; return type required
public Dragin(){
^
1 error

What's happening here is that the compiler sees that the name of the method is different from the name of the class. Aha, it says, this isn't a constructor since it doesn't have the same name as the class. So it must be an instance method. Hey, instance methods need a type! There's no type! Then it prints the error message.

Note that spelling errors include capitalization. So having a class named Dragon with a constructor called dragon() would cause the same error.

For more about constructor methods, see Multiple Constructor Methods.
StumbleUpon