|
Now, every time we make an object of class Person, we know that we can define each of these bits of data (name, age, and address) for every different Person we make. Notice that classes can hold data that is of other class types, and these types can be built in to the Java API, or they can be other classes that you define yourself.
The
name
variable is a variable of type String.
String
is a class representing a character sequence that has already been written for you as part of the Java API. If Sun didn't provide the API, you would have to define the String type yourself. Because
String
s are things that everyone needs, it is very
The age variable is an int primitive type. Because Java supports autoboxing and unboxing of primitives, it acts like an int primitive when that's what you need, and it acts like an Integer wrapper class when that is what you need. The address variable is declared to be of type Address. Address is not a class defined in the Java API, so the assumption is that you have defined a class called Address that has properties of its own (such as street , zipCode , or whatever). If you don't make that class first, the Person class won't compile. You generally can get the value of each member of an object using the dot operator. I write "generally" because you might not have direct access to data from other classes, which is a matter of visibility , which we'll deal with later. For now, it is enough to know that our data members in the Person class are all declared to have public visibility, which means that any other class can read or write their values. Let's make an object, set the value of its members, and then get the value of each member and print it to the console. I'm going to leave the Address member out of this one for now, so we can compile it. Person.java
//declare the class
public class Person {
//define our two variables
public String name;
public int age;
//main method is required starting point
//for Java programs
public static void main(String[] args) {
//make the object of type Person
Person p = new Person();
//we can now refer to this particular object
//as "p" to do stuff with it
//set the value of the name member
p.name = "Eben Hewitt";
//set the value of the age member.
p.age = 32;
//print out our values
System.out.println("The person named " + p.name +
" is " + p.age + " years old.");
} //end of main method
} //end of class
The output of running the Person class is like this: The person named Eben Hewitt is 32 years old.
Having compiled the class, you will have generated a second file on your disk called Person class. This is the executable bytecode that the Java runtime interprets. You can open that class file and view it in a text editor, though many of the
Let's make it a little more complicated, and define a second class in the same source file (the one that ends in .java). This will be our Address class. Now that we know what an Address is, we can specify that a Person has a member of type Address. Hey, I know this code is starting to look a little long. But a lot of it is comments. I think it's important to read what is happening line by line; it helps put all of the pieces together, which is also why I'm showing the complete listing. So don't worry. PersonWithAddress.java
public class PersonWithAddress {
//define our two variables
public String name;
public int age;
//added the gnarly new Address member!
public Address address;
//main method is required starting point
//for Java programs
public static void main(String[] args) {
//make the object of type PersonWithAddress
//PersonWithAddress person = new //PersonWithAddress();
//we can now refer to this particular object
//as "person" to do stuff with it
//set the value of the name member
person.name = "Bill Gates";
//set the value of the age member.
person.age = 32;
/*
set the address. wait! it's a class itself. so we have to make an instance of
This outputs the following: The person named Bill Gates lives in Muncie, Indiana. Classes Have Behavior (Methods)
We use the word behavior colloquially to refer to actions that someone
Each method (sometimes called a function, or in VB, a subroutine) represents a different little bit of functionality. Here is what makes up a method.
A method does one job. Like variables, methods have
They have a degree of visibility , which indicates what other classes (if any) can call them. Methods can have visibility of default (no visibility explicitly declared), public , protected , or private . Methods also have a return type that indicates the one value that represents the result of performing the method. Methods can take zero or more parameters , or values that you pass into them. Parameters are declared using the type of variable you want to accept and an identifier for each variable for use inside the method body. Methods might throw exceptions, but we talk about that in Chapter 21, "Handling Exceptions." Methods have a body , which consists of zero or more statements in between curly braces that do the work of the method. Here is an example:
public class Person {
private int age;
public int getAge() {
return age;
}
public void setAge(int ageIn) {
age = ageIn;
}
}
This class has one member variable and two methods: getAge() and setAge() . The getAge() method declaration says it returns an int , and the body of the method indeed does nothing but return the value of the age member, which is of type int . The getAge() method's visibility is declared to be public , so any other class is allowed to use the getAge() method. This method takes no arguments at all. The second method is called setAge() , and it also has a visibility of public . But it has a return type of void , which means that the method does some stuff but does not return any result to the caller. A constructor is a special type of method that gives you control over how you create your objects. We'll talk about those in a bit. Return TypesIt may seem obvious, but if you say that a method will return a value, it must return a value. You can't do this:
public int getAge() {
int i = 7;
} //won't compile!
This method will not compile because you say you're going to do something (return a value) and you don't keep your promise. By the same token, the following is also illegal:
public int getAge() {
return; //won't compile!
}
Here, we say we're returning an int , but we don't: returning nothing is not the same as returning something (any kind of int ). The following, however, is legal:
public void ohWellWhateverNeverMind() {
return ;
}
You can do that because you are returning nothing, which is what you say you will return. That method is equivalent to this:
public void hahaha() { }
Which is also legal. You don't have to have anything in the body. Though that doesn't do much for you except help you compile your class if you aren't sure what code to put there yet. Both are equivalent to the following, which is also legal:
public void allYourBase(String areBelongToUs) {
; ; ;
; ;
}
Again, you can do it, but it's probably not too common. If you see that sort of thing a lot at your job, you might reconsider
Methods can return the result of evaluating an expression that contains literals, like this:
public int getADumbOldNumber() {
return 7 * 54;
}
Methods can return a literal, like this:
public String getMessage() {
return "I love you, man...";
}
Methods can return the result of a call to another method, which is just another form of an expression.
public double getRandomNumber() {
return Math.random();
}
If you think it would be a good idea to be very explicit about what you're doing to help your reader, or if your method consists of a number of statements, you can return a result that you hold in a variable, like this:
public double getRandomNumber() {
double d = Math.random();
return d;
}
Methods can return a type that can be converted at runtime into the declared return type. For example, a
float
is a floating point type that holds 32 bits of data. A
double
holds 64 bits of data. That means that any
float
can fit into a
double
container. That means that the following is
public double getIt() {
float f = 16F;
return f;
}
Although the number you create inside the method body is of type float , it is a double when the method returns. So, here's a quick quiz. Is the following legal?
public float getFloat() {
return 16F;
}
//call it from somewhere:
double myNumber = getFloat();
Here, we call a method expecting a
double
to be returned, and the method returns a
float
. This code
will
compile. That is because the variable (
myNumber
) to which we assign the result of the
getFloat()
method can hold a
double
-
Starting Programs: The Main() MethodThere is a method that is used as the starting place for all Java programs called the main method. It is so called in C++ and C# as well. When you start a Java program, you call the java command and pass it the name of the class containing the main method. The signature of this method is like this: public static void main(String[] args) . Let's break that down.
The method is
public
so it can be called from
Say you had a program that launched a rover to Mars. You might have
Params.java
public class Params {
public static void main(String[] args) {
if (args.length == 2){
String a = args[0];
String b = args[1];
System.out.println("Your first argument: " + a);
System.out.println("Your second
argument: " + b);
} else {
System.out.println("You must supply
two arguments!");
}
}
}
The output of this class when called like this: java Params Spirit Opportunity , is Your first argument: Spirit Your second argument: Opportunity The output when called like this: java Params (with no arguments), is You must supply two arguments! The main method does not explicitly throw any exceptions. If an exception occurs inside the main method, it is thrown out to the JVM, which then halts and prints a stack trace. The stack trace is the list of methods called up to the point where the exception was thrown, in descending order. You can put a try/catch block around the main method if you want, but it will have no effect. Let's add a few regular old non-main methods to our Person class. PersonWithMethods.java
public class PersonWithMethods {
//define some members
public String name;
private boolean isJerk = false;
//program starts running here
public static void main(String[] args) {
//create one person
PersonWithMethods p1 = new
PersonWithMethods();
//set the member's value with dot operator
p1.name = "Aristotle";
//call the method on the current object
p1.setJerk(true);
//create a different person object
PersonWithMethods p2 = new
//PersonWithMethods();
p2.name = "Hegel";
//pass in a boolean parameter to the method
p2.setJerk(false);
//find out what we know about them.
//note the explicit call to the method //toString()
System.out.println(p1.toString());
//note the IMPLICIT call to toString!
//both this and the previous statement
//are equivalent
System.out.println(p2);
}
//in this method, we set the value of the
//isJerk member variable
public void setJerk(boolean isJerk) {
this.isJerk = isJerk;
} //end method
public String isJerk(){
if (this.isJerk == true)
return "a jerky jerk";
else
return "totally a non-jerk";
}
public String toString(){
return name + " is " + isJerk();
}
} //end class
The preceding code outputs the following: Aristotle is a jerky jerk Hegel is totally a non-jerk We make two separate objects here, which we refer to as p1 and p2. Each object keeps its own data. They each have a different value for name and a different value for isJerk . The methods we call perform the same operation, but return different results based on the member data.
The
toString()
method is what is called an
override
of the method called
toString()
in the parent class of Person, which is
java.lang.Object
. See Chapter 12, "Inheritance," for more on that. I
Static MethodsA static method is one that is called on the class itself, as opposed to a method that is called on an instance of the class. The main method is a static method, which makes sense, cuz there cannot be any object instances before the program starts up and begins making objects! The way to make a static method is to declare it using the static keyword.
public static void something() { ... }
You can then call the method without needing a particular instance of the class. Static methods are used frequently in Java programming. They are used when they can always perform the same operation, regardless of the current program state. That's because static methods can't know anything about the current program state ”they aren't called on object instances. They are said to be called on the class itself. Consider this to help make the point: The methods of the java.lang.Math class are all static. It is easy to see why. They always do the exact same thing, regardless of what is happening in the world. You can call a static method by using the dot operator after the class name, like this: Math.random();
The preceding method returns a more-or-less random primitive
double
with a value greater than or equal to 0.0 and less than 1.0. You don't need an instance of an object to do that work, because the result will always be the same, no matter what the state of some hypothetical Math object might be. It's not even meaningful when you think about it. What would be the state of Math itself where it would make a difference what number the random method returned? There is no particular instance of the Math class that would make a difference to the
sin
method, which returns the trigonometric sine of an angle. That operation is always going to be done the same way. By the same reasoning, consider the following methods of the
java.lang.Math
class:
abs()
returns the absolute value of a number,
atan()
returns the arc tangent of an angle,
asin()
returns the arc sine of an angle,
pow()
returns the value of the first argument raised to the power of the second argument, and so on. There are a couple
{% if main.adsdop %}{% include 'adsenceinline.tpl' %}{% endif %} Let's now look at a few details regarding static methods. Here's something that could throw you for a loop: you can call a static method on an object. However, doing so does not in any regard change its functionality. It is merely a convenience. It is preferable to call static methods on the name of the class to indicate that they are static methods. But that's a convention that will likely die as developers start adopting the new static import facility in Java 5.0 (discussed in Chapter 11, "Classes Reloaded"). Put a different way: calling Person p = new Person(); p.myStaticMethod(); Is identical to calling Person.myStaticMethod(); Here is a more complete example: StaticStuff.java
public class StaticStuff {
public static void main(String[] args) {
System.out.println(myStaticMethod
(Math.random()));
}
private static String myStaticMethod(double num){
return "Your lucky lottery number is: " +
(int)(num * 100);
}
}
The output is something like: Your lucky lottery number is: 63 The StaticStuff class features three static methods. This is a good example because it shows how to use static methods, but it also shows how you can nest method calls to simplify your program's look and streamline it.
The first static method,
main()
, is always static and starts the program. We don't pass any arguments into the program, so its
String[]
parameter is empty. We then call the method
println()
on the static member
out
of the
System
class. We call
myStaticMethod()
, passing in as a parameter the result of the third static method call ”the one to
Math.random()
. We take the random result generated by the call to
Math.random()
, pass it into
myStaticMethod()
, which returns a String that contains the
Final MethodsIn Java, it is possible to extend the functionality of a class by subclassing. For example, we can decide that we want a more specific kind of Person, and then write a class that inherits Person variables and methods. Such a class might be called Programmer. A Programmer is a Person, with an address and a name and all, but a Programmer has other characteristics and things he knows how to do that are not common to all people. When you create a subclass, it is possible to override the methods in the superclass. That is, the Programmer class could choose to redefine a method that is implemented in the superclass. We did this earlier by having our implementation of the Person class override the toString method of the Object class. If you don't want to allow a particular method to ever be redefined in a subclass, you declare it final . Consider the following method that might return the absolute value of an integer. public final abs(int a);
Here, we want to declare this method
final
, because it would be horrible if we allowed mathematical functions that should determine their results in an
Note that classes, methods, and variables can all be declared final . If a class is declared final , all of the methods within the class are implicitly final as well. Because the java.lang.Math class is declared final , none of the methods in it need to be declared final . In the case of classes, it means that no other class can extend it. In the case of a method, as here, it means no subclass can override it. In the case of a variable, it means that its value cannot be reassigned after it has been assigned.
Rules for Declaring MethodsWe will discuss visibility modifiers in the next section. Classes, methods, and variables all have visibility. You can explicitly declare a method as having public , private , or protected visibility. If you do not explicitly indicate the visibility, the compiler will make your method (or class or member) to have default visibility. You don't write "default." For example, the following are all valid:
public void getAge() {}
void setAge() {}
private doWork(){}
Methods are defined by their signatures. A signature consists of
You cannot have two methods with the same signature in the same class; the runtime wouldn't know which one to call. You can have two methods with the same name ”that is called overloading and is discussed later.
You cannot start a method name with a number or any weird characters like a carat or a % sign. Just don't be trying to do that. You can
start
a method name with an
Which of the following method declarations are valid or invalid?
public void _23() {}
void doinIt(String theThing) {}
int private HEY_SUCKER(){}
protected Address setaddress(theAddress) {}
The first is valid, because you can start a method name with an underscore. The second is valid, because leaving out the visibility modifier is okay, and it will be set to "default" visibility. The third method will not compile. Although the compiler doesn't care how you capitalize your methods, you cannot declare the return type ( int ) before the visibility modifier ( private ). The last one will not compile because the parameter is not declared to have a type. You can name the parameter that a method accepts according to the rules for naming any other variable. In Java 5.0, you can also declare generic methods. These are an advanced topic, however, and if you're interested in using them, please check out the Generics topic in the companion book to this one, More Java Garage . Also, check out the Glossary in this book that contains some stuff about using generics. That might be enough about those rules. Hmm. Yes, that's enough. Conventions for Declaring Methods
Please follow these conventions for using methods. It will make your day go by with less unpleasantness. Methods are by convention named with an initial lowercase letter, and
public void someSortOfLongMethodName() {}
Method names should be descriptive. Although you are
allowed
to name your method
x()
, this is a real drag for everybody. Don't make the poor
Make your method names that are used just for returning a value get ThingReturned () like this: getAddress() . Such a method is called an accessor. If the value returned is a boolean value, you write is Thing () like this: isJerk() . Accessors are typically only this:
public int getAge() {
return age;
}
Make your method names that are primarily used for setting the value of a member start with "set," like this: set ThingToSet () . A typical mutator looks like this:
public void setAge(int ageIn) {
this.age = ageIn;
}
At the Java Academy for Super Nerds they brainwash you into saying "accessor" and "mutator" to refer to these kinds of methods. Nobody cool uses those terms though. All of the cool
The guidelines for naming parameters to methods is the same as for any regular variable name. Say you have a setter method. Call it setAge() , and it takes a parameter of type int like this: void setAge(int age) . Typically, you will be setting the value of a class member. Name the method parameter after the class member, and name the method set Member () . So you have a method that ends up looking like this:
void setAge(int age) {
this.age = age;
}
The keyword this is used to refer to the current instance. In VB, that's when you write "Me." It means "the current object," and in this context it helps us tell the difference between the member variable and the parameter. Some people slightly change the parameter name. My friend Vic does it by suffixing the word In to the variable.
void setAge(int ageIn) {
age = ageIn;
}
Then, you don't have to use the this keyword. You can do that if you want. It might help to keep everything straight at first. We'll talk about this in a mo'. Classes Have a Home (Package)A package in Java is a namespace that allows classes to be identified. Packages allow you to have two different classes of the same name within the same application if the package name is different. The purpose of packages is to resolve naming conflicts. To place your class in a package, use the package keyword. The package keyword acts as a logical namespace to separate different classes that go together. It allows you to put them in groups. A package also corresponds to a physical location within a directory structure. This is different than in a language like C#, where the namespaces are purely virtual. In C#, you can put your class in any old directory and call the package whatever you want. Not so in Java. If you have a class called Kitty and you want to put it in a package called pets, the Java class file must physically reside in a folder called pets.
It
If you explicitly put your class in a package, the package statement must be the first line of code in the source file that is not a comment. Comments can go first. But nothing else. Like this:
package net.javagarage;
public class MyClass {...}
The preceding statement means that there is a folder at the root of the application called net and it contains a folder named javagarage and that folder contains your class file. I can now write a class called MyClass and put it in the com.loveboat package, and the compiler and runtime will be able to tell them apart. If you have more than one class in a source file, the package statement applies to every class in the source file. If you do not explicitly place your class in a package, it will reside in the default package. There is a convention for naming packages that just about everyone follows. It goes like this: Take your company's Web site and use its top-level domain as the top-level package. For example, in my case, my domain is called javagarage.net, so the TLD is net, so the top-level package is net. Then, put the domain name as the second highest-level package name. Don't put any classes at all in either of these packages. But now, after you're two deep, you usually name your application. Unless there is a subdomain that is relevant. Then, you can use the subdomain. For example, if I made an ecommerce site, I might put those classes in net.javagarage.store , and I could start defining the custom packages that I think I'll want in my app. Maybe products could have its own package, and checkout could have its own package. And like that.
For instance, I have classes in the
net.javagarage.demo.inherit
package that demonstrate using inheritance. I have classes in the
net.javagarage.demo.classes
package that demonstrate using classes. And so on. This is a good convention, based on the fact that a company's domain name is
It is important to take care with naming your packages, and organizing your classes within them. It is not uncommon for developers to
Classes Have VisibilityUp until now, we have put the keyword public in front of our class declaration, our method declarations, and our member declarations. We have mentioned different levels of visibility, but not what each of them means.
There are four levels of visibility in Java. They are listed here from least restrictive to most
What level of access does the following method have?
int[] getMedicalRecords(Person p) { ... }
Default. Only classes in the same package can use this method. If you try to access something that you aren't allowed to, the compiler will tell you with a message saying, "Can't access classname ". If you want to know more about classes, check out Chapter 11. |