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.
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, top-down) 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. This is a key concept that 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.
IT Programming Solutions
Computer Programming and Web Development
Overview of Java - Abstraction - Lesson 2
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 or MP3
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.
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 or MP3
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.
Overview of Java - Object-Oriented Programming - Lesson 1
A Culture of Innovation
Since the beginning, Java has been at the center of a culture of innovation. Its original release
redefined programming for the Internet. The Java Virtual Machine (JVM) and bytecode
changed the way we think about security and portability. The applet (and then the servlet)
made the Web come alive. The Java Community Process (JCP) redefined the way that new
ideas are assimilated into the language. The world of Java has never stood still for very long.
Java SE 8 is the latest release in Java’s ongoing, dynamic history
Object-oriented programming (OOP) is at the core of Java. In fact, all Java programs are to
at least some extent object-oriented. OOP is so integral to Java that it is best to understand
its basic principles before you begin writing even simple Java programs. Therefore, this
chapter begins with a discussion of the theoretical aspects of OOP.
Two Paradigms
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.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 object-oriented 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.
Since the beginning, Java has been at the center of a culture of innovation. Its original release
redefined programming for the Internet. The Java Virtual Machine (JVM) and bytecode
changed the way we think about security and portability. The applet (and then the servlet)
made the Web come alive. The Java Community Process (JCP) redefined the way that new
ideas are assimilated into the language. The world of Java has never stood still for very long.
Java SE 8 is the latest release in Java’s ongoing, dynamic history
Object-oriented programming (OOP) is at the core of Java. In fact, all Java programs are to
at least some extent object-oriented. OOP is so integral to Java that it is best to understand
its basic principles before you begin writing even simple Java programs. Therefore, this
chapter begins with a discussion of the theoretical aspects of OOP.
Two Paradigms
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.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 object-oriented 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.
The History and Evolution of Java - The Java Buzzwords - Lesson 7
The Java Buzzwords
No discussion of Java’s history is complete without a look at the Java buzzwords. Although
the fundamental forces that necessitated the invention of Java are portability and security,
other factors also played an important role in molding the final form of the language. The
key considerations were summed up by the Java team in the following list of buzzwords:
Two of these buzzwords have already been discussed: secure and portable. Let’s examine
what each of the others implies.
Simple
Java was designed to be easy for the professional programmer to learn and use effectively.
Assuming that you have some programming experience, you will not find Java hard to master.
If you already understand the basic concepts of object-oriented programming, learning Java
will be even easier. Best of all, if you are an experienced C++ programmer, moving to Java will
require very little effort. Because Java inherits the C/C++ syntax and many of the objectoriented
features of C++, most programmers have little trouble learning Java.
Object-Oriented
Although influenced by its predecessors, Java was not designed to be source-code compatible
with any other language. This allowed the Java team the freedom to design with a blank
slate. One outcome of this was a clean, usable, pragmatic approach to objects. Borrowing
liberally from many seminal object-software environments of the last few decades, Java
manages to strike a balance between the purist’s “everything is an object” paradigm and
the pragmatist’s “stay out of my way” model. The object model in Java is simple and easy to
extend, while primitive types, such as integers, are kept as high-performance nonobjects.
Robust
The multiplatformed environment of the Web places extraordinary demands on a
program, because the program must execute reliably in a variety of systems. Thus, the
ability to create robust programs was given a high priority in the design of Java. To gain
reliability, Java restricts you in a few key areas to force you to find your mistakes early in
program development. At the same time, Java frees you from having to worry about many
of the most common causes of programming errors. Because Java is a strictly typed
language, it checks your code at compile time. However, it also checks your code at run
time. Many hard-to-track-down bugs that often turn up in hard-to-reproduce run-time
situations are simply impossible to create in Java. Knowing that what you have written
will behave in a predictable way under diverse conditions is a key feature of Java.
To better understand how Java is robust, consider two of the main reasons for program
failure: memory management mistakes and mishandled exceptional conditions (that is,
run-time errors). Memory management can be a difficult, tedious task in traditional programming environments. For example, in C/C++, the programmer will often manually
allocate and free all dynamic memory. This sometimes leads to problems, because
programmers will either forget to free memory that has been previously allocated or,
worse, try to free some memory that another part of their code is still using. Java virtually
eliminates these problems by managing memory allocation and deallocation for you. (In fact,
deallocation is completely automatic, because Java provides garbage collection for unused
objects.) Exceptional conditions in traditional environments often arise in situations such
as division by zero or “file not found,” and they must be managed with clumsy and hard-toread
constructs. Java helps in this area by providing object-oriented exception handling. In
a well-written Java program, all run-time errors can—and should—be managed by your
program.
Multithreaded
Java was designed to meet the real-world requirement of creating interactive, networked
programs. To accomplish this, Java supports multithreaded programming, which allows you
to write programs that do many things simultaneously. The Java run-time system comes with
an elegant yet sophisticated solution for multiprocess synchronization that enables you to
construct smoothly running interactive systems. Java’s easy-to-use approach to multithreading
allows you to think about the specific behavior of your program, not the multitasking
subsystem.
Architecture-Neutral
A central issue for the Java designers was that of code longevity and portability. At the time
of Java’s creation, one of the main problems facing programmers was that no guarantee
existed that if you wrote a program today, it would run tomorrow—even on the same
machine. Operating system upgrades, processor upgrades, and changes in core system
resources can all combine to make a program malfunction. The Java designers made
several hard decisions in the Java language and the Java Virtual Machine in an attempt to
alter this situation. Their goal was “write once; run anywhere, any time, forever.” To a great
extent, this goal was accomplished.
Interpreted and High Performance
As described earlier, Java enables the creation of cross-platform programs by compiling into
an intermediate representation called Java bytecode. This code can be executed on any
system that implements the Java Virtual Machine. Most previous attempts at cross-platform
solutions have done so at the expense of performance. As explained earlier, the Java
bytecode was carefully designed so that it would be easy to translate directly into native
machine code for very high performance by using a just-in-time compiler. Java run-time
systems that provide this feature lose none of the benefits of the platform-independent code.
Distributed
Java is designed for the distributed environment of the Internet because it handles TCP/IP
protocols. In fact, accessing a resource using a URL is not much different from accessing a
file. Java also supports Remote Method Invocation (RMI). This feature enables a program to
invoke methods across a network.
Dynamic
Java programs carry with them substantial amounts of run-time type information that is used
to verify and resolve accesses to objects at run time. This makes it possible to dynamically link
code in a safe and expedient manner. This is crucial to the robustness of the Java environment,
in which small fragments of bytecode may be dynamically updated on a running system.
No discussion of Java’s history is complete without a look at the Java buzzwords. Although
the fundamental forces that necessitated the invention of Java are portability and security,
other factors also played an important role in molding the final form of the language. The
key considerations were summed up by the Java team in the following list of buzzwords:
- Simple
- Secure
- Portable
- Object-oriented
- Robust
- Multithreaded
- Architecture-neutral
- Interpreted
- High performance
- Distributed
- Dynamic
Two of these buzzwords have already been discussed: secure and portable. Let’s examine
what each of the others implies.
Simple
Java was designed to be easy for the professional programmer to learn and use effectively.
Assuming that you have some programming experience, you will not find Java hard to master.
If you already understand the basic concepts of object-oriented programming, learning Java
will be even easier. Best of all, if you are an experienced C++ programmer, moving to Java will
require very little effort. Because Java inherits the C/C++ syntax and many of the objectoriented
features of C++, most programmers have little trouble learning Java.
Object-Oriented
Although influenced by its predecessors, Java was not designed to be source-code compatible
with any other language. This allowed the Java team the freedom to design with a blank
slate. One outcome of this was a clean, usable, pragmatic approach to objects. Borrowing
liberally from many seminal object-software environments of the last few decades, Java
manages to strike a balance between the purist’s “everything is an object” paradigm and
the pragmatist’s “stay out of my way” model. The object model in Java is simple and easy to
extend, while primitive types, such as integers, are kept as high-performance nonobjects.
Robust
The multiplatformed environment of the Web places extraordinary demands on a
program, because the program must execute reliably in a variety of systems. Thus, the
ability to create robust programs was given a high priority in the design of Java. To gain
reliability, Java restricts you in a few key areas to force you to find your mistakes early in
program development. At the same time, Java frees you from having to worry about many
of the most common causes of programming errors. Because Java is a strictly typed
language, it checks your code at compile time. However, it also checks your code at run
time. Many hard-to-track-down bugs that often turn up in hard-to-reproduce run-time
situations are simply impossible to create in Java. Knowing that what you have written
will behave in a predictable way under diverse conditions is a key feature of Java.
To better understand how Java is robust, consider two of the main reasons for program
failure: memory management mistakes and mishandled exceptional conditions (that is,
run-time errors). Memory management can be a difficult, tedious task in traditional programming environments. For example, in C/C++, the programmer will often manually
allocate and free all dynamic memory. This sometimes leads to problems, because
programmers will either forget to free memory that has been previously allocated or,
worse, try to free some memory that another part of their code is still using. Java virtually
eliminates these problems by managing memory allocation and deallocation for you. (In fact,
deallocation is completely automatic, because Java provides garbage collection for unused
objects.) Exceptional conditions in traditional environments often arise in situations such
as division by zero or “file not found,” and they must be managed with clumsy and hard-toread
constructs. Java helps in this area by providing object-oriented exception handling. In
a well-written Java program, all run-time errors can—and should—be managed by your
program.
Multithreaded
Java was designed to meet the real-world requirement of creating interactive, networked
programs. To accomplish this, Java supports multithreaded programming, which allows you
to write programs that do many things simultaneously. The Java run-time system comes with
an elegant yet sophisticated solution for multiprocess synchronization that enables you to
construct smoothly running interactive systems. Java’s easy-to-use approach to multithreading
allows you to think about the specific behavior of your program, not the multitasking
subsystem.
Architecture-Neutral
A central issue for the Java designers was that of code longevity and portability. At the time
of Java’s creation, one of the main problems facing programmers was that no guarantee
existed that if you wrote a program today, it would run tomorrow—even on the same
machine. Operating system upgrades, processor upgrades, and changes in core system
resources can all combine to make a program malfunction. The Java designers made
several hard decisions in the Java language and the Java Virtual Machine in an attempt to
alter this situation. Their goal was “write once; run anywhere, any time, forever.” To a great
extent, this goal was accomplished.
Interpreted and High Performance
As described earlier, Java enables the creation of cross-platform programs by compiling into
an intermediate representation called Java bytecode. This code can be executed on any
system that implements the Java Virtual Machine. Most previous attempts at cross-platform
solutions have done so at the expense of performance. As explained earlier, the Java
bytecode was carefully designed so that it would be easy to translate directly into native
machine code for very high performance by using a just-in-time compiler. Java run-time
systems that provide this feature lose none of the benefits of the platform-independent code.
Distributed
Java is designed for the distributed environment of the Internet because it handles TCP/IP
protocols. In fact, accessing a resource using a URL is not much different from accessing a
file. Java also supports Remote Method Invocation (RMI). This feature enables a program to
invoke methods across a network.
Dynamic
Java programs carry with them substantial amounts of run-time type information that is used
to verify and resolve accesses to objects at run time. This makes it possible to dynamically link
code in a safe and expedient manner. This is crucial to the robustness of the Java environment,
in which small fragments of bytecode may be dynamically updated on a running system.
The History and Evolution of Java - Servlets: Java on the Server Side - Lesson 6
Servlets: Java on the Server Side
As useful as applets can be, they are just one half of the client/server equation. Not long
after the initial release of Java, it became obvious that Java would also be useful on the
server side. The result was the servlet. A servlet is a small program that executes on the
server. Just as applets dynamically extend the functionality of a web browser, servlets
dynamically extend the functionality of a web server. Thus, with the advent of the servlet,
Java spanned both sides of the client/server connection.
Servlets are used to create dynamically generated content that is then served to the
client. For example, an online store might use a servlet to look up the price for an item in a
database. The price information is then used to dynamically generate a web page that is sent
to the browser. Although dynamically generated content is available through mechanisms
such as CGI (Common Gateway Interface), the servlet offers several advantages, including
increased performance.
Because servlets (like all Java programs) are compiled into bytecode and executed by
the JVM, they are highly portable. Thus, the same servlet can be used in a variety of
different server environments. The only requirements are that the server support the JVM
and a servlet container.
As useful as applets can be, they are just one half of the client/server equation. Not long
after the initial release of Java, it became obvious that Java would also be useful on the
server side. The result was the servlet. A servlet is a small program that executes on the
server. Just as applets dynamically extend the functionality of a web browser, servlets
dynamically extend the functionality of a web server. Thus, with the advent of the servlet,
Java spanned both sides of the client/server connection.
Servlets are used to create dynamically generated content that is then served to the
client. For example, an online store might use a servlet to look up the price for an item in a
database. The price information is then used to dynamically generate a web page that is sent
to the browser. Although dynamically generated content is available through mechanisms
such as CGI (Common Gateway Interface), the servlet offers several advantages, including
increased performance.
Because servlets (like all Java programs) are compiled into bytecode and executed by
the JVM, they are highly portable. Thus, the same servlet can be used in a variety of
different server environments. The only requirements are that the server support the JVM
and a servlet container.
Subscribe to:
Posts (Atom)