Saturday, September 6, 2008

java I unit

Object-Oriented Programming
Object-oriented programming is at the core of Java. In fact, all Java programs are objectoriented
—this isn't an option the way that it is in C++, for example. OOP is so integral to
Java that you must understand its basic principles before you can write even simple Java
programs. Therefore, this chapter begins with a discussion of the theoretical aspects of
OOP.
Two Paradigms
As you know, all computer programs consist of two elements: code and data.
Furthermore, a program can be conceptually organized around its code or around its
data. That is, some programs are written around "what is happening" and others are
written around "who is being affected." These are the two paradigms that govern how a
program is constructed. The first way is called the process-oriented model. This approach
characterizes a program as a series of linear steps (that is, code). The process-oriented
model can be thought of as code acting on data. Procedural languages such as C employ
this model to considerable success. However, as mentioned in Chapter 1, problems with
this approach appear as programs grow larger and more complex.
To manage increasing complexity, the second approach, called object-oriented
programming, was conceived. Object-oriented programming organizes a program around
its data (that is, objects) and a set of well-defined interfaces to that data. An objectoriented
program can be characterized as data controlling access to code. As you will
see, by switching the controlling entity to data, you can achieve several organizational
benefits.
Abstraction
An essential element of object-oriented programming is abstraction. Humans manage
complexity through abstraction. For example, people do not think of a car as a set of tens
of thousands of individual parts. They think of it as a well-defined object with its own
unique behavior. This abstraction allows people to use a car to drive to the grocery store
without being overwhelmed by the complexity of the parts that form the car. They can
ignore the details of how the engine, transmission, and braking systems work. Instead
they are free to utilize the object as a whole.
A powerful way to manage abstraction is through the use of hierarchical classifications.
This allows you to layer the semantics of complex systems, breaking them into more
manageable pieces. From the outside, the car is a single object. Once inside, you see
that the car consists of several subsystems: steering, brakes, sound system, seat belts,
heating, cellular phone, and so on. In turn, each of these subsystems is made up of more
specialized units. For instance, the sound system consists of a radio, a CD player, and/or
a tape player. The point is that you manage the complexity of the car (or any other
complex system) through the use of hierarchical abstractions.
Hierarchical abstractions of complex systems can also be applied to computer programs.
The data from a traditional process-oriented program can be transformed by abstraction
into its component objects. A sequence of process steps can become a collection of
messages between these objects. Thus, each of these objects describes its own unique
behavior. You can treat these objects as concrete entities that respond to messages
telling them to do something. This is the essence of object-oriented programming.
Object-oriented concepts form the heart of Java just as they form the basis for human
understanding. It is important that you understand how these concepts translate into
programs. As you will see, object-oriented programming is a powerful and natural
paradigm for creating programs that survive the inevitable changes accompanying the life
cycle of any major software project, including conception, growth, and aging. For
example, once you have well-defined objects and clean, reliable interfaces to those
objects, you can gracefully decommission or replace parts of an older system without
fear.
The Three OOP Principles
All object-oriented programming languages provide mechanisms that help you implement
the object-oriented model. They are encapsulation, inheritance, and polymorphism. Let's
take a look at these concepts now.
Encapsulation
Encapsulation is the mechanism that binds together code and the data it manipulates,
and keeps both safe from outside interference and misuse. One way to think about
encapsulation is as a protective wrapper that prevents the code and data from being
arbitrarily accessed by other code defined outside the wrapper. Access to the code and
data inside the wrapper is tightly controlled through a well-defined interface. To relate this
to the real world, consider the automatic transmission on an automobile. It encapsulates
hundreds of bits of information about your engine, such as how much you are
accelerating, the pitch of the surface you are on, and the position of the shift lever. You,
as the user, have only one method of affecting this complex encapsulation: by moving the
gear-shift lever. You can't affect the transmission by using the turn signal or windshield
wipers, for example. Thus, the gear-shift lever is a well-defined (indeed, unique) interface
to the transmission. Further, what occurs inside the transmission does not affect objects
outside the transmission. For example, shifting gears does not turn on the headlights!
Because an automatic transmission is encapsulated, dozens of car manufacturers can
implement one in any way they please. However, from the driver's point of view, they all
work the same. This same idea can be applied to programming. The power of
encapsulated code is that everyone knows how to access it and thus can use it
regardless of the implementation details—and without fear of unexpected side effects.
In Java the basis of encapsulation is the class. Although the class will be examined in
great detail later in this book, the following brief discussion will be helpful now. A class
defines the structure and behavior (data and code) that will be shared by a set of objects.
Each object of a given class contains the structure and behavior defined by the class, as
if it were stamped out by a mold in the shape of the class. For this reason, objects are
sometimes referred to as instances of a class. Thus, a class is a logical construct; an
object has physical reality.
When you create a class, you will specify the code and data that constitute that class.
Collectively, these elements are called members of the class. Specifically, the data
defined by the class are referred to as member variables or instance variables. The code
that operates on that data is referred to as member methods or just methods. (If you are
familiar with C/C++, it may help to know that what a Java programmer calls a method, a
C/C++ programmer calls a function.) In properly written Java programs, the methods
define how the member variables can be used. This means that the behavior and
interface of a class are defined by the methods that operate on its instance data.
Since the purpose of a class is to encapsulate complexity, there are mechanisms for
hiding the complexity of the implementation inside the class. Each method or variable in a
class may be marked private or public. The public interface of a class represents
everything that external users of the class need to know, or may know. The private
methods and data can only be accessed by code that is a member of the class.
Therefore, any other code that is not a member of the class cannot access a private
method or variable. Since the private members of a class may only be accessed by other
parts of your program through the class' public methods, you can ensure that no
improper actions take place. Of course, this means that the public interface should be
carefully designed not to expose too much of the inner workings of a class (see Figure 2-
1).
Inheritance
Inheritance is the process by which one object acquires the properties of another object.
This is important because it supports the concept of hierarchical classification. As
mentioned earlier, most knowledge is made manageable by hierarchical (that is, topdown)
classifications. For example, a Golden Retriever is part of the classification dog,
which in turn is part of the mammal class, which is under the larger class animal. Without
the use of hierarchies, each object would need to define all of its characteristics explicitly.
However, by use of inheritance, an object need only define those qualities that make it
unique within its class. It can inherit its general attributes from its parent. Thus, it is the
inheritance mechanism that makes it possible for one object to be a specific instance of a
more general case. Let's take a closer look at this process.
Most people naturally view the world as made up of objects that are related to each other
in a hierarchical way, such as animals, mammals, and dogs. If you wanted to describe
animals in an abstract way, you would say they have some attributes, such as size,
intelligence, and type of skeletal system. Animals also have certain behavioral aspects;
they eat, breathe, and sleep. This description of attributes and behavior is the class
definition for animals.
If you wanted to describe a more specific class of animals, such as mammals, they would
have more specific attributes, such as type of teeth, and mammary glands. This is known
as a subclass of animals, where animals are referred to as mammals' superclass.
Since mammals are simply more precisely specified animals, they inherit all of the
attributes from animals. A deeply inherited subclass inherits all of the attributes from each
of its ancestors in the class hierarchy.
Inheritance interacts with encapsulation as well. If a given class encapsulates some
attributes, then any subclass will have the same attributes plus any that it adds as part of
its specialization (see Figure 2-2). This is a key concept which lets object-oriented
programs grow in complexity linearly rather than geometrically. A new subclass inherits
all of the attributes of all of its ancestors. It does not have unpredictable interactions with
the majority of the rest of the code in the system.
Polymorphism
Polymorphism (from the Greek, meaning "many forms") is a feature that allows one
interface to be used for a general class of actions. The specific action is determined by
the exact nature of the situation. Consider a stack (which is a last-in, first-out list). You
might have a program that requires three types of stacks. One stack is used for integer
values, one for floating-point values, and one for characters. The algorithm that
implements each stack is the same, even though the data being stored differs. In a non–
object-oriented language, you would be required to create three different sets of stack
routines, with each set using different names. However, because of polymorphism, in
Java you can specify a general set of stack routines that all share the same names.
More generally, the concept of polymorphism is often expressed by the phrase "one
interface, multiple methods." This means that it is possible to design a generic interface
to a group of related activities. This helps reduce complexity by allowing the same
interface to be used to specify a general class of action. It is the compiler's job to select
the specific action (that is, method) as it applies to each situation. You, the programmer,
do not need to make this selection manually. You need only remember and utilize the
general interface.
Extending the dog analogy, a dog's sense of smell is polymorphic. If the dog smells a cat,
it will bark and run after it. If the dog smells its food, it will salivate and run to its bowl. The
same sense of smell is at work in both situations. The difference is what is being smelled,
that is, the type of data being operated upon by the dog's nose! This same general
concept can be implemented in Java as it applies to methods within a Java program.
Polymorphism, Encapsulation, and Inheritance Work Together
When properly applied, polymorphism, encapsulation, and inheritance combine to
produce a programming environment that supports the development of far more robust
and scaleable programs than does the process-oriented model. A well-designed
hierarchy of classes is the basis for reusing the code in which you have invested time and
effort developing and testing. Encapsulation allows you to migrate your implementations
over time without breaking the code that depends on the public interface of your classes.
Polymorphism allows you to create clean, sensible, readable, and resilient code.
Of the two real-world examples, the automobile more completely illustrates the power of
object-oriented design. Dogs are fun to think about from an inheritance standpoint, but
cars are more like programs. All drivers rely on inheritance to drive different types
(subclasses) of vehicles. Whether the vehicle is a school bus, a Mercedes sedan, a
Porsche, or the family minivan, drivers can all more or less find and operate the steering
wheel, the brakes, and the accelerator. After a bit of gear grinding, most people can even
manage the difference between a stick shift and an automatic, because they
fundamentally understand their common superclass, the transmission.
People interface with encapsulated features on cars all the time. The brake and gas
pedals hide an incredible array of complexity with an interface so simple you can operate
them with your feet! The implementation of the engine, the style of brakes, and the size of
the tires have no effect on how you interface with the class definition of the pedals.
The final attribute, polymorphism, is clearly reflected in the ability of car manufacturers to
offer a wide array of options on basically the same vehicle. For example, you can get an
antilock braking system or traditional brakes, power or rack-and-pinion steering, 4-, 6-, or
8-cylinder engines. Either way, you will still press the break pedal to stop, turn the
steering wheel to change direction, and press the accelerator when you want to move.
The same interface can be used to control a number of different implementations.
As you can see, it is through the application of encapsulation, inheritance, and
polymorphism that the individual parts are transformed into the object known as a car.
The same is also true of computer programs. By the application of object-oriented
principles, the various parts of a complex program can be brought together to form a
cohesive, robust, maintainable whole.
As mentioned at the start of this section, every Java program is object-oriented. Or, put
more precisely, every Java program involves encapsulation, inheritance, and
polymorphism. Although the short example programs shown in the rest of this chapter and
in the next few chapters may not seem to exhibit all of these features, they are
nevertheless present. As you will see, many of the features supplied by Java are part of its
built-in class libraries, which do make extensive use of encapsulation, inheritance, and
polymorphism.
A First Simple Program
Now that the basic object-oriented underpinning of Java has been discussed, let's look at
some actual Java programs. Let's start by compiling and running the short sample
program shown here. As you will see, this involves a little more work than you might
imagine.
/*
This is a simple Java program.
Call this file "Example.java".
*/
class Example {
// Your program begins with a call to main().
public static void main(String args[]) {
System.out.println("This is a simple Java program.");
}
}
Note
The descriptions that follow use the standard JDK (Java Developer's Kit),
which is available from Sun Microsystems. If you are using a different Java
development environment, then you may need to follow a different procedure
for compiling and executing Java programs. In this case, consult your
compiler's user manuals for details.
Entering the Program
For most computer languages, the name of the file that holds the source code to a
program is arbitrary. However, this is not the case with Java. The first thing that you must
learn about Java is that the name you give to a source file is very important. For this
example, the name of the source file should be Example.java. Let's see why.
In Java, a source file is officially called a compilation unit. It is a text file that contains one
or more class definitions. The Java compiler requires that a source file use the .java
filename extension. Notice that the file extension is four characters long. As you might
guess, your operating system must be capable of supporting long filenames. This means
that DOS and Windows 3.1 are not capable of supporting Java (at least at this time).
However, Windows 95/98 and Windows NT work just fine.
As you can see by looking at the program, the name of the class defined by the program
is also Example. This is not a coincidence. In Java, all code must reside inside a class.
By convention, the name of that class should match the name of the file that holds the
program. You should also make sure that the capitalization of the filename matches the
class name. The reason for this is that Java is case-sensitive. At this point, the
convention that filenames correspond to class names may seem arbitrary. However, this
convention makes it easier to maintain and organize your programs.
Compiling the Program
To compile the Example program, execute the compiler, javac, specifying the name of
the source file on the command line, as shown here:
C:\\>javac Example.java
The javac compiler creates a file called Example.class that contains the bytecode
version of the program. As discussed earlier, the Java bytecode is the intermediate
representation of your program that contains instructions the Java interpreter will
execute. Thus, the output of javac is not code that can be directly executed.
To actually run the program, you must use the Java interpreter, called java. To do so,
pass the class name Example as a command-line argument, as shown here:
C:\\>java Example
When the program is run, the following output is displayed:
This is a simple Java program.
When Java source code is compiled, each individual class is put into its own output file
named after the class and using the .class extension. This is why it is a good idea to give
your Java source files the same name as the class they contain—the name of the source
file will match the name of the .class file. When you execute the Java interpreter as just
shown, you are actually specifying the name of the class that you want the interpreter to
execute. It will automatically search for a file by that name that has the .class extension.
If it finds the file, it will execute the code contained in the specified class.
A Closer Look at the First Sample Program
Although Example.java is quite short, it includes several key features which are common
to all Java programs. Let's closely examine each part of the program.
The program begins with the following lines:
/*
This is a simple Java program.
Call this file "Example.java".
*/
This is a comment. Like most other programming languages, Java lets you enter a
remark into a program's source file. The contents of a comment are ignored by the
compiler. Instead, a comment describes or explains the operation of the program to
anyone who is reading its source code. In this case, the comment describes the program
and reminds you that the source file should be called Example.java. Of course, in real
applications, comments generally explain how some part of the program works or what a
specific feature does.
Java supports three styles of comments. The one shown at the top of the program is
called a multiline comment. This type of comment must begin with /* and end with */.
Anything between these two comment symbols is ignored by the compiler. As the name
suggests, a multiline comment may be several lines long.
The next line of code in the program is shown here:
class Example {
This line uses the keyword class to declare that a new class is being defined. Example
is an identifier that is the name of the class. The entire class definition, including all of its
members, will be between the opening curly brace ({) and the closing curly brace (}). The
use of the curly braces in Java is identical to the way they are used in C and C++. For the
moment, don't worry too much about the details of a class except to note that in Java, all
program activity occurs within one. This is one reason why all Java programs are (at least
a little bit) object-oriented.
The next line in the program is the single-line comment, shown here:
// Your program begins with a call to main().
This is the second type of comment supported by Java. A single-line comment begins
with a // and ends at the end of the line. As a general rule, programmers use multiline
comments for longer remarks and single-line comments for brief, line-by-line descriptions.
The next line of code is shown here:
public static void main(String args[]) {
This line begins the main( ) method. As the comment preceding it suggests, this is the
line at which the program will begin executing. All Java applications begin execution by
calling main( ). (This is just like C/C++.) The exact meaning of each part of this line
cannot be given now, since it involves a detailed understanding of Java's approach to
encapsulation. However, since most of the examples in the first part of this book will use
this line of code, let's take a brief look at each part now.
The public keyword is an access specifier, which allows the programmer to control the
visibility of class members. When a class member is preceded by public, then that
member may be accessed by code outside the class in which it is declared. (The
opposite of public is private, which prevents a member from being used by code defined
outside of its class.) In this case, main( ) must be declared as public, since it must be
called by code outside of its class when the program is started. The keyword static
allows main( ) to be called without having to instantiate a particular instance of the class.
This is necessary since main( ) is called by the Java interpreter before any objects are
made. The keyword void simply tells the compiler that main( ) does not return a value.
As you will see, methods may also return values. If all this seems a bit confusing, don't
worry. All of these concepts will be discussed in detail in subsequent chapters.
As stated, main( ) is the method called when a Java application begins. Keep in mind
that Java is case-sensitive. Thus, Main is different from main. It is important to
understand that the Java compiler will compile classes that do not contain a main( )
method. But the Java interpreter has no way to run these classes. So, if you had typed
Main instead of main, the compiler would still compile your program. However, the Java
interpreter would report an error because it would be unable to find the main( ) method.
Any information that you need to pass to a method is received by variables specified
within the set of parentheses that follow the name of the method. These variables are
called parameters. If there are no parameters required for a given method, you still need
to include the empty parentheses. In main( ), there is only one parameter, albeit a
complicated one. String args[ ] declares a parameter named args, which is an array of
instances of the class String. (Arrays are collections of similar objects.) Objects of type
String store character strings. In this case, args receives any command-line arguments
present when the program is executed. This program does not make use of this
information, but other programs shown later in this book will.
The last character on the line is the {. This signals the start of main( )'s body. All of the
code that comprises a method will occur between the method's opening curly brace and
its closing curly brace.
One other point: main( ) is simply a starting place for the interpreter. A complex program
will have dozens of classes, only one of which will need to have a main( ) method to get
things started. When you begin creating applets—Java programs that are embedded in
Web browsers—you won't use main( ) at all, since the Web browser uses a different
means of starting the execution of applets.
The next line of code is shown here. Notice that it occurs inside main( ).
System.out.println("This is a simple Java program.");
This line outputs the string "This is a simple Java program." followed by a new line on the
screen. Output is actually accomplished by the built-in println( ) method. In this case,
println( ) displays the string which is passed to it. As you will see, println( ) can be used
to display other types of information, too. The line begins with System.out. While too
complicated to explain in detail at this time, briefly, System is a predefined class that
provides access to the system, and out is the output stream that is connected to the
console.
As you have probably guessed, console output (and input) is not used frequently in real
Java programs and applets. Since most modern computing environments are windowed
and graphical in nature, console I/O is used mostly for simple, utility programs and for
demonstration programs. Later in this book, you will learn other ways to generate output
using Java. But for now, we will continue to use the console I/O methods.
Notice that the println( ) statement ends with a semicolon. All statements in Java end
with a semicolon. The reason that the other lines in the program do not end in a
semicolon is that they are not, technically, statements.
The first } in the program ends main( ), and the last } ends the Example class definition.



Exceptions are the customary way in Java to indicate to a calling method that an abnormal condition has occurred. This article is a companion piece to this month's Design Techniques installment, which discusses how to use exceptions appropriately in your programs and designs. Look to this companion article for a tutorial on the nuts and bolts of what exceptions are and how they work in the Java language and virtual machine.
When a method encounters an abnormal condition (an exception condition) that it can't handle itself, it may throw an exception. Throwing an exception is like throwing a beeping, flashing red ball to indicate there is a problem that can't be handled where it occurred. Somewhere, you hope, this ball will be caught and the problem will be dealt with. Exceptions are caught by handlers positioned along the thread's method invocation stack. If the calling method isn't prepared to catch the exception, it throws the exception up to its calling method, and so on. If one of the threads of your program throws an exception that isn't caught by any method along the method invocation stack, that thread will expire. When you program in Java, you must position catchers (the exception handlers) strategically, so your program will catch and handle all exceptions from which you want your program to recover.
Exception classes
In Java, exceptions are objects. When you throw an exception, you throw an object. You can't throw just any object as an exception, however -- only those objects whose classes descend from Throwable. Throwable serves as the base class for an entire family of classes, declared in java.lang, that your program can instantiate and throw. A small part of this family is shown in Figure 1.
As you can see in Figure 1, Throwable has two direct subclasses, Exception and Error. Exceptions (members of the Exception family) are thrown to signal abnormal conditions that can often be handled by some catcher, though it's possible they may not be caught and therefore could result in a dead thread. Errors (members of the Error family) are usually thrown for more serious problems, such as OutOfMemoryError, that may not be so easy to handle. In general, code you write should throw only exceptions, not errors. Errors are usually thrown by the methods of the Java API, or by the Java virtual machine itself.
Figure 1. A partial view of the Throwable family
In addition to throwing objects whose classes are declared in java.lang, you can throw objects of your own design. To create your own class of throwable objects, you need only declare it as a subclass of some member of the Throwable family. In general, however, the throwable classes you define should extend class Exception. They should be "exceptions." The reasoning behind this rule will be explained later in this article.
Whether you use an existing exception class from java.lang or create one of your own depends upon the situation. In some cases, a class from java.lang will do just fine. For example, if one of your methods is invoked with an invalid argument, you could throw IllegalArgumentException, a subclass of RuntimeException in java.lang.
·

No comments: